<!DOCTYPE html>
<html class="writer-html5" lang="en" >
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Compilation &mdash; pytket-manual  documentation</title>
      <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
      <link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
      <link rel="stylesheet" href="_static/jupyter-sphinx.css" type="text/css" />
      <link rel="stylesheet" href="_static/thebelab.css" type="text/css" />
  <!--[if lt IE 9]>
    <script src="_static/js/html5shiv.min.js"></script>
  <![endif]-->
  
        <script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
        <script src="_static/jquery.js"></script>
        <script src="_static/underscore.js"></script>
        <script src="_static/doctools.js"></script>
        <script src="_static/thebelab-helper.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.4/require.min.js"></script>
        <script src="https://unpkg.com/@jupyter-widgets/html-manager@^0.20.0/dist/embed-amd.js"></script>
        <script async="async" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
    <script src="_static/js/theme.js"></script>
    <link rel="index" title="Index" href="genindex.html" />
    <link rel="search" title="Search" href="search.html" />
    <link rel="next" title="Noise and the Quantum Circuit Model" href="manual_noise.html" />
    <link rel="prev" title="Running on Backends" href="manual_backend.html" /> 
</head>

<body class="wy-body-for-nav"> 
  <div class="wy-grid-for-nav">
    <nav data-toggle="wy-nav-shift" class="wy-nav-side">
      <div class="wy-side-scroll">
        <div class="wy-side-nav-search" >
            <a href="index.html" class="icon icon-home"> pytket-manual
          </a>
<div role="search">
  <form id="rtd-search-form" class="wy-form" action="search.html" method="get">
    <input type="text" name="q" placeholder="Search docs" />
    <input type="hidden" name="check_keywords" value="yes" />
    <input type="hidden" name="area" value="default" />
  </form>
</div>
        </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
              <ul class="current">
<li class="toctree-l1"><a class="reference internal" href="manual_intro.html">What is tket?</a></li>
<li class="toctree-l1"><a class="reference internal" href="manual_circuit.html">Circuit Construction</a></li>
<li class="toctree-l1"><a class="reference internal" href="manual_backend.html">Running on Backends</a></li>
<li class="toctree-l1 current"><a class="current reference internal" href="#">Compilation</a><ul>
<li class="toctree-l2"><a class="reference internal" href="#predicates">Predicates</a></li>
<li class="toctree-l2"><a class="reference internal" href="#rebases">Rebases</a></li>
<li class="toctree-l2"><a class="reference internal" href="#placement">Placement</a></li>
<li class="toctree-l2"><a class="reference internal" href="#routing">Routing</a></li>
<li class="toctree-l2"><a class="reference internal" href="#decomposing-structures">Decomposing Structures</a></li>
<li class="toctree-l2"><a class="reference internal" href="#optimisations">Optimisations</a></li>
<li class="toctree-l2"><a class="reference internal" href="#combinators">Combinators</a></li>
<li class="toctree-l2"><a class="reference internal" href="#predefined-sequences">Predefined Sequences</a></li>
<li class="toctree-l2"><a class="reference internal" href="#guidance-for-combining-passes">Guidance for Combining Passes</a></li>
<li class="toctree-l2"><a class="reference internal" href="#initial-and-final-maps">Initial and Final Maps</a></li>
<li class="toctree-l2"><a class="reference internal" href="#advanced-topics">Advanced Topics</a><ul>
<li class="toctree-l3"><a class="reference internal" href="#compiling-symbolic-circuits">Compiling Symbolic Circuits</a></li>
<li class="toctree-l3"><a class="reference internal" href="#partial-compilation">Partial Compilation</a></li>
<li class="toctree-l3"><a class="reference internal" href="#measurement-reduction">Measurement Reduction</a></li>
<li class="toctree-l3"><a class="reference internal" href="#contextual-optimisations">Contextual Optimisations</a><ul>
<li class="toctree-l4"><a class="reference internal" href="#initial-simplification">Initial simplification</a></li>
<li class="toctree-l4"><a class="reference internal" href="#removal-of-discarded-operations">Removal of discarded operations</a></li>
<li class="toctree-l4"><a class="reference internal" href="#commutation-of-measured-classical-maps">Commutation of measured classical maps</a></li>
<li class="toctree-l4"><a class="reference internal" href="#contextual-optimisation-in-practice">Contextual optimisation in practice</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="manual_noise.html">Noise and the Quantum Circuit Model</a></li>
<li class="toctree-l1"><a class="reference internal" href="manual_assertion.html">Assertion</a></li>
</ul>
<p class="caption" role="heading"><span class="caption-text">More documentation:</span></p>
<ul>
<li class="toctree-l1"><a class="reference external" href="https://cqcl.github.io/tket/pytket/api/index.html">pytket</a></li>
</ul>

        </div>
      </div>
    </nav>

    <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
          <i data-toggle="wy-nav-top" class="fa fa-bars"></i>
          <a href="index.html">pytket-manual</a>
      </nav>

      <div class="wy-nav-content">
        <div class="rst-content">
          <div role="navigation" aria-label="Page navigation">
  <ul class="wy-breadcrumbs">
      <li><a href="index.html" class="icon icon-home"></a> &raquo;</li>
      <li>Compilation</li>
      <li class="wy-breadcrumbs-aside">
            <a href="_sources/manual_compiler.rst.txt" rel="nofollow"> View page source</a>
      </li>
  </ul>
  <hr/>
</div>
          <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
           <div itemprop="articleBody">
             
  <div class="section" id="compilation">
<h1>Compilation<a class="headerlink" href="#compilation" title="Permalink to this headline"></a></h1>
<p>So far, we have already covered enough to be able to design the <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> s we want to run, submit them to a <code class="xref py py-class docutils literal notranslate"><span class="pre">Backend</span></code>, and interpret the results in a meaningful way. This is all you need if you want to just try out a quantum computer, run some toy examples and observe some basic results. We actually glossed over a key step in this process by using the <code class="xref py py-meth docutils literal notranslate"><span class="pre">Backend.get_compiled_circuit()</span></code> method. The compilation step maps from the universal computer abstraction presented at <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> construction to the restricted fragment supported by the target <code class="xref py py-class docutils literal notranslate"><span class="pre">Backend</span></code>, and knowing what a compiler can do to your program can help reduce the burden of design and improve performance on real devices.</p>
<p>The necessity of compilation maps over from the world of classical computation: it is much easier to design correct programs when working with higher-level constructions that aren’t natively supported, and it shouldn’t require a programmer to be an expert in the exact device architecture to achieve good performance. There are many possible low-level implementations on the device for each high-level program, which vary in the time and resources taken to execute. However, because QPUs are analog devices, the implementation can have a massive impact on the quality of the final outcomes as a result of changing how susceptible the system is to noise. Using a good compiler and choosing the methods appropriately can automatically find a better low-level implementation. Each aspect of the compilation procedure is exposed through <code class="docutils literal notranslate"><span class="pre">pytket</span></code> to provide users with a way to have full control over what is applied and how.</p>
<p>The primary goals of compilation are two-fold: solving the constraints of the <code class="xref py py-class docutils literal notranslate"><span class="pre">Backend</span></code> to get from the abstract model to something runnable, and optimising/simplifying the <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> to make it faster, smaller, and less prone to noise. Every step in compilation can generally be split up into one of these two categories (though even the constraint solving steps could have multiple solutions over which we could optimise for noise).</p>
<p>Each compiler pass inherits from the <code class="xref py py-class docutils literal notranslate"><span class="pre">BasePass</span></code> class, capturing a method of transforming a <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code>. The main functionality is built into the <code class="xref py py-meth docutils literal notranslate"><span class="pre">BasePass.apply()</span></code> method, which applies the transformation to a <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> in-place. The <code class="xref py py-meth docutils literal notranslate"><span class="pre">Backend.get_compiled_circuit()</span></code> method is a wrapper around the <code class="xref py py-meth docutils literal notranslate"><span class="pre">BasePass.apply()</span></code> from the <code class="xref py py-class docutils literal notranslate"><span class="pre">Backend</span></code> ‘s recommended pass sequence. This chapter will explore these compiler passes, the different kinds of constraints they are used to solve and optimisations they apply, to help you identify which ones are appropriate for a given task.</p>
<div class="section" id="predicates">
<h2>Predicates<a class="headerlink" href="#predicates" title="Permalink to this headline"></a></h2>
<p>Solving the constraints of the target <code class="xref py py-class docutils literal notranslate"><span class="pre">Backend</span></code> is the essential goal of compilation, so our choice of passes is mostly driven by this set of constraints. We already saw in the last chapter that the <code class="xref py py-attr docutils literal notranslate"><span class="pre">Backend.required_predicates</span></code> property gives a collection of <code class="xref py py-class docutils literal notranslate"><span class="pre">Predicate</span></code> s, describing the necessary properties a <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> must satisfy in order to be run.</p>
<p>Each <code class="xref py py-class docutils literal notranslate"><span class="pre">Predicate</span></code> can be constructed on its own to impose tests on <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> s during construction.</p>
<div class="jupyter_cell jupyter_container docutils container">
<div class="cell_input code_cell docutils container">
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pytket</span> <span class="kn">import</span> <span class="n">Circuit</span><span class="p">,</span> <span class="n">OpType</span>
<span class="kn">from</span> <span class="nn">pytket.predicates</span> <span class="kn">import</span> <span class="n">GateSetPredicate</span><span class="p">,</span> <span class="n">NoMidMeasurePredicate</span>
<span class="n">circ</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">Rx</span><span class="p">(</span><span class="mf">0.2</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">Rz</span><span class="p">(</span><span class="o">-</span><span class="mf">0.7</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">measure_all</span><span class="p">()</span>

<span class="n">gateset</span> <span class="o">=</span> <span class="n">GateSetPredicate</span><span class="p">({</span><span class="n">OpType</span><span class="o">.</span><span class="n">Rx</span><span class="p">,</span> <span class="n">OpType</span><span class="o">.</span><span class="n">CX</span><span class="p">,</span> <span class="n">OpType</span><span class="o">.</span><span class="n">Rz</span><span class="p">,</span> <span class="n">OpType</span><span class="o">.</span><span class="n">Measure</span><span class="p">})</span>
<span class="n">midmeasure</span> <span class="o">=</span> <span class="n">NoMidMeasurePredicate</span><span class="p">()</span>

<span class="nb">print</span><span class="p">(</span><span class="n">gateset</span><span class="o">.</span><span class="n">verify</span><span class="p">(</span><span class="n">circ</span><span class="p">))</span>
<span class="nb">print</span><span class="p">(</span><span class="n">midmeasure</span><span class="o">.</span><span class="n">verify</span><span class="p">(</span><span class="n">circ</span><span class="p">))</span>

<span class="n">circ</span><span class="o">.</span><span class="n">S</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>

<span class="nb">print</span><span class="p">(</span><span class="n">gateset</span><span class="o">.</span><span class="n">verify</span><span class="p">(</span><span class="n">circ</span><span class="p">))</span>
<span class="nb">print</span><span class="p">(</span><span class="n">midmeasure</span><span class="o">.</span><span class="n">verify</span><span class="p">(</span><span class="n">circ</span><span class="p">))</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-none notranslate"><div class="highlight"><pre><span></span>True
True
False
False
</pre></div>
</div>
</div>
</div>
<table class="docutils align-default">
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<thead>
<tr class="row-odd"><th class="head"><p>Common <code class="xref py py-class docutils literal notranslate"><span class="pre">Predicate</span></code></p></th>
<th class="head"><p>Constraint</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td><p><code class="xref py py-class docutils literal notranslate"><span class="pre">GateSetPredicate</span></code></p></td>
<td><div class="line-block">
<div class="line">Every gate is within a set of allowed
<code class="xref py py-class docutils literal notranslate"><span class="pre">OpType</span></code> s</div>
</div>
</td>
</tr>
<tr class="row-odd"><td><p><code class="xref py py-class docutils literal notranslate"><span class="pre">ConnectivityPredicate</span></code></p></td>
<td><div class="line-block">
<div class="line">Every multi-qubit gate acts on
adjacent qubits according to some
connectivity graph</div>
</div>
</td>
</tr>
<tr class="row-even"><td><p><code class="xref py py-class docutils literal notranslate"><span class="pre">DirectednessPredicate</span></code></p></td>
<td><div class="line-block">
<div class="line">Extends
<code class="xref py py-class docutils literal notranslate"><span class="pre">ConnectivityPredicate</span></code>
where <code class="docutils literal notranslate"><span class="pre">OpType::CX</span></code> gates are only
supported in a specific orientation
between adjacent qubits</div>
</div>
</td>
</tr>
<tr class="row-odd"><td><p><code class="xref py py-class docutils literal notranslate"><span class="pre">NoClassicalControlPredicate</span></code></p></td>
<td><div class="line-block">
<div class="line">The <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> does not
contain any gates that act
conditionally on classical data</div>
</div>
</td>
</tr>
<tr class="row-even"><td><p><code class="xref py py-class docutils literal notranslate"><span class="pre">NoMidMeasurePredicate</span></code></p></td>
<td><div class="line-block">
<div class="line">All <code class="docutils literal notranslate"><span class="pre">OpType::Measure</span></code> gates act at
the end of the <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code>
(there are no subsequent gates on
either the <code class="xref py py-class docutils literal notranslate"><span class="pre">Qubit</span></code> measured
or the <code class="xref py py-class docutils literal notranslate"><span class="pre">Bit</span></code> written to)</div>
</div>
</td>
</tr>
</tbody>
</table>
<p>When applying passes, you may find that you apply some constraint-solving pass to satisfy a particular <code class="xref py py-class docutils literal notranslate"><span class="pre">Predicate</span></code>, but then a subsequent pass will invalidate it by, for example, introducing gates of different gate types or changing which qubits interact via multi-qubit gates. To help understand and manage this, each pass has a set of pre-conditions that specify the requirements assumed on the <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> in order for the pass to successfully be applied, and a set of post-conditions that specify which <code class="xref py py-class docutils literal notranslate"><span class="pre">Predicate</span></code> s are guaranteed to hold for the outputs and which are invalidated or preserved by the pass. These can be viewed in the API reference for each pass.</p>
</div>
<div class="section" id="rebases">
<h2>Rebases<a class="headerlink" href="#rebases" title="Permalink to this headline"></a></h2>
<p>One of the simplest constraints to solve for is the <code class="xref py py-class docutils literal notranslate"><span class="pre">GateSetPredicate</span></code>, since we can just substitute each gate in a <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> with an equivalent sequence of gates in the target gateset according to some known gate decompositions. In <code class="docutils literal notranslate"><span class="pre">pytket</span></code>, such passes are referred to as “rebases”. The intention here is to perform this translation naively, leaving the optimisation of gate sequences to other passes. Rebases can be applied to any <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> and will preserve every structural <code class="xref py py-class docutils literal notranslate"><span class="pre">Predicate</span></code>, only changing the types of gates used.</p>
<div class="jupyter_cell jupyter_container docutils container">
<div class="cell_input code_cell docutils container">
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pytket</span> <span class="kn">import</span> <span class="n">Circuit</span>
<span class="kn">from</span> <span class="nn">pytket.passes</span> <span class="kn">import</span> <span class="n">RebaseTket</span>
<span class="n">circ</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">Rx</span><span class="p">(</span><span class="mf">0.3</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">Ry</span><span class="p">(</span><span class="o">-</span><span class="mf">0.9</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">CZ</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">S</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">measure_all</span><span class="p">()</span>

<span class="n">RebaseTket</span><span class="p">()</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">circ</span><span class="p">)</span>

<span class="nb">print</span><span class="p">(</span><span class="n">circ</span><span class="o">.</span><span class="n">get_commands</span><span class="p">())</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-none notranslate"><div class="highlight"><pre><span></span>[tk1(0, 0.3, 0) q[0];, tk1(0.5, 3.1, 3.5) q[1];, tk1(0.5, 0.5, 0.5) q[1];, CX q[0], q[1];, tk1(0, 0, 0.5) q[0];, tk1(0.5, 0.5, 0.5) q[1];, CX q[1], q[0];, Measure q[0] --&gt; c[0];, Measure q[1] --&gt; c[1];]
</pre></div>
</div>
</div>
</div>
<p>A number of standard rebase passes are available for common gatesets.</p>
<table class="docutils align-default">
<colgroup>
<col style="width: 33%" />
<col style="width: 67%" />
</colgroup>
<thead>
<tr class="row-odd"><th class="head"><p>Pass</p></th>
<th class="head"><p>Gateset</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td><p><code class="xref py py-class docutils literal notranslate"><span class="pre">RebaseCirq</span></code></p></td>
<td><div class="line-block">
<div class="line">CZ, PhasedX and Rz - primitives on some Google
devices</div>
</div>
</td>
</tr>
<tr class="row-odd"><td><p><code class="xref py py-class docutils literal notranslate"><span class="pre">RebaseHQS</span></code></p></td>
<td><div class="line-block">
<div class="line">ZZMax, PhasedX and Rz - primitives on hardware
from Honeywell Quantum Systems</div>
</div>
</td>
</tr>
<tr class="row-even"><td><p><code class="xref py py-class docutils literal notranslate"><span class="pre">RebaseProjectQ</span></code></p></td>
<td><div class="line-block">
<div class="line">SWAP, CRz, CX, CZ, H, X, Y, Z, S, T, V, Rx, Ry
and Rz - gates supported by the ProjectQ simulator</div>
</div>
</td>
</tr>
<tr class="row-odd"><td><p><code class="xref py py-class docutils literal notranslate"><span class="pre">RebasePyZX</span></code></p></td>
<td><div class="line-block">
<div class="line">SWAP, CX, CZ, H, X, Z, S, T, Rx and Rz - gates
supported by the PyZX software package</div>
</div>
</td>
</tr>
<tr class="row-even"><td><p><code class="xref py py-class docutils literal notranslate"><span class="pre">RebaseQuil</span></code></p></td>
<td><div class="line-block">
<div class="line">CZ, Rx and Rz - primitives on hardware from Rigetti</div>
</div>
</td>
</tr>
<tr class="row-odd"><td><p><code class="xref py py-class docutils literal notranslate"><span class="pre">RebaseTket</span></code></p></td>
<td><div class="line-block">
<div class="line">CX and TK1 - preferred internal gateset for many
<code class="docutils literal notranslate"><span class="pre">pytket</span></code> compiler passes</div>
</div>
</td>
</tr>
</tbody>
</table>
<p>This set of rebases are provided for convenience, but the facility is available to define a rebase for an arbitrary gateset. Using <code class="xref py py-class docutils literal notranslate"><span class="pre">RebaseCustom</span></code>, we can provide an arbitrary set of multi-qubit and single-qubit gates. Rather than requiring custom decompositions to be provided for every gate type, it is sufficient to just give them <code class="docutils literal notranslate"><span class="pre">OpType.CX</span></code> and <code class="docutils literal notranslate"><span class="pre">OpType.TK1</span></code> - for any gate in a given <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code>, it is either already in the target gateset, or we can use known decompositions to obtain a <code class="docutils literal notranslate"><span class="pre">OpType.CX</span></code> and <code class="docutils literal notranslate"><span class="pre">OpType.TK1</span></code> representation and then map this to the target gateset.</p>
<div class="jupyter_cell jupyter_container docutils container">
<div class="cell_input code_cell docutils container">
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pytket</span> <span class="kn">import</span> <span class="n">Circuit</span><span class="p">,</span> <span class="n">OpType</span>
<span class="kn">from</span> <span class="nn">pytket.passes</span> <span class="kn">import</span> <span class="n">RebaseCustom</span>

<span class="n">multiq_gates</span> <span class="o">=</span> <span class="p">{</span><span class="n">OpType</span><span class="o">.</span><span class="n">CY</span><span class="p">,</span> <span class="n">OpType</span><span class="o">.</span><span class="n">ZZPhase</span><span class="p">}</span>
<span class="n">singleq_gates</span> <span class="o">=</span> <span class="p">{</span><span class="n">OpType</span><span class="o">.</span><span class="n">Rz</span><span class="p">,</span> <span class="n">OpType</span><span class="o">.</span><span class="n">Ry</span><span class="p">}</span>
<span class="n">cx_in_cy</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="n">cx_in_cy</span><span class="o">.</span><span class="n">Rz</span><span class="p">(</span><span class="mf">0.5</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">CY</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">Rz</span><span class="p">(</span><span class="o">-</span><span class="mf">0.5</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">tk1_to_rzry</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">c</span><span class="p">):</span>
    <span class="n">circ</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
    <span class="n">circ</span><span class="o">.</span><span class="n">Rz</span><span class="p">(</span><span class="n">c</span> <span class="o">+</span> <span class="mf">0.5</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">Ry</span><span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">Rz</span><span class="p">(</span><span class="n">a</span> <span class="o">-</span> <span class="mf">0.5</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">circ</span>

<span class="n">custom</span> <span class="o">=</span> <span class="n">RebaseCustom</span><span class="p">(</span><span class="n">multiq_gates</span><span class="p">,</span> <span class="n">cx_in_cy</span><span class="p">,</span> <span class="n">singleq_gates</span><span class="p">,</span> <span class="n">tk1_to_rzry</span><span class="p">)</span>

<span class="n">circ</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">X</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">Ry</span><span class="p">(</span><span class="mf">0.2</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">add_gate</span><span class="p">(</span><span class="n">OpType</span><span class="o">.</span><span class="n">ZZPhase</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.83</span><span class="p">,</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">])</span><span class="o">.</span><span class="n">Rx</span><span class="p">(</span><span class="mf">0.6</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>

<span class="n">custom</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">circ</span><span class="p">)</span>

<span class="nb">print</span><span class="p">(</span><span class="n">circ</span><span class="o">.</span><span class="n">get_commands</span><span class="p">())</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-none notranslate"><div class="highlight"><pre><span></span>[Rz(0.5) q[0];, Rz(0.5) q[1];, Ry(1) q[0];, Rz(3.5) q[0];, CY q[0], q[1];, Rz(3.5) q[1];, Ry(0.2) q[1];, ZZPhase(3.17) q[2], q[1];, Rz(0.5) q[2];, Ry(0.6) q[2];, Rz(3.5) q[2];]
</pre></div>
</div>
</div>
</div>
</div>
<div class="section" id="placement">
<span id="compiler-placement"></span><h2>Placement<a class="headerlink" href="#placement" title="Permalink to this headline"></a></h2>
<p>Initially, a <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> designed without a target device in mind will be expressed in terms of actions on a set of “logical qubits” - those with semantic meaning to the computation. A <cite>placement</cite> (or <cite>initial mapping</cite>) is a map from these logical qubits to the physical qubits of the device that will be used to carry them. A given placement may be preferred over another if the connectivity of the physical qubits better matches the interactions between the logical qubits caused by multi-qubit gates, or if the selection of physical qubits has better noise characteristics. All of the information for connectivity and noise characteristics of a given <code class="xref py py-class docutils literal notranslate"><span class="pre">Backend</span></code> is wrapped up in a <code class="xref py py-class docutils literal notranslate"><span class="pre">BackendInfo</span></code> object by the <code class="xref py py-attr docutils literal notranslate"><span class="pre">Backend.backend_info</span></code> property.</p>
<p>The placement only specifies where the logical qubits will be at the start of execution, which is not necessarily where they will end up on termination. Other compiler passes may choose to permute the qubits in the middle of a <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> to either exploit further optimisations or enable interactions between logical qubits that were not assigned to adjacent physical qubits.</p>
<p>A placement pass will act in place on a <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> by renaming the qubits from their logical names (the <code class="xref py py-class docutils literal notranslate"><span class="pre">UnitID</span></code> s used at circuit construction) to their physical addresses (the <code class="xref py py-class docutils literal notranslate"><span class="pre">UnitID</span></code> s recognised by the <code class="xref py py-class docutils literal notranslate"><span class="pre">Backend</span></code>). Classical data is never renamed.</p>
<div class="jupyter_cell jupyter_container docutils container">
<div class="cell_input code_cell docutils container">
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pytket</span> <span class="kn">import</span> <span class="n">Circuit</span>
<span class="kn">from</span> <span class="nn">pytket.extensions.qiskit</span> <span class="kn">import</span> <span class="n">IBMQBackend</span>
<span class="kn">from</span> <span class="nn">pytket.passes</span> <span class="kn">import</span> <span class="n">PlacementPass</span>
<span class="kn">from</span> <span class="nn">pytket.predicates</span> <span class="kn">import</span> <span class="n">ConnectivityPredicate</span>
<span class="kn">from</span> <span class="nn">pytket.routing</span> <span class="kn">import</span> <span class="n">GraphPlacement</span>
<span class="n">circ</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="mi">4</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">H</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">H</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">H</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">V</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">Rz</span><span class="p">(</span><span class="o">-</span><span class="mf">0.37</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">H</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">H</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">H</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">Vdg</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">measure_all</span><span class="p">()</span>

<span class="n">backend</span> <span class="o">=</span> <span class="n">IBMQBackend</span><span class="p">(</span><span class="s2">&quot;ibmq_quito&quot;</span><span class="p">)</span>
<span class="n">place</span> <span class="o">=</span> <span class="n">PlacementPass</span><span class="p">(</span><span class="n">GraphPlacement</span><span class="p">(</span><span class="n">backend</span><span class="o">.</span><span class="n">backend_info</span><span class="o">.</span><span class="n">architecture</span><span class="p">))</span>
<span class="n">place</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">circ</span><span class="p">)</span>

<span class="nb">print</span><span class="p">(</span><span class="n">circ</span><span class="o">.</span><span class="n">get_commands</span><span class="p">())</span>
<span class="nb">print</span><span class="p">(</span><span class="n">ConnectivityPredicate</span><span class="p">(</span><span class="n">backend</span><span class="o">.</span><span class="n">backend_info</span><span class="o">.</span><span class="n">architecture</span><span class="p">)</span><span class="o">.</span><span class="n">verify</span><span class="p">(</span><span class="n">circ</span><span class="p">))</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-none notranslate"><div class="highlight"><pre><span></span>[H node[0];, H node[1];, H node[3];, V node[4];, CX node[0], node[1];, CX node[1], node[3];, CX node[3], node[4];, Rz(3.63*PI) node[4];, CX node[3], node[4];, CX node[1], node[3];, Vdg node[4];, Measure node[4] --&gt; c[3];, CX node[0], node[1];, H node[3];, Measure node[3] --&gt; c[2];, H node[0];, H node[1];, Measure node[0] --&gt; c[0];, Measure node[1] --&gt; c[1];]
True
</pre></div>
</div>
</div>
</div>
<p>In this example, the placement was able to find an exact match for the connectivity onto the device.</p>
<p>In some circumstances, the best location is not fully determined immediately and is deferred until later in compilation. This gives rise to a partial placement (the map from logical qubits to physical qubits is a partial function, where undefined qubits are renamed into an <code class="docutils literal notranslate"><span class="pre">unplaced</span></code> register).</p>
<div class="jupyter_cell jupyter_container docutils container">
<div class="cell_input code_cell docutils container">
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pytket</span> <span class="kn">import</span> <span class="n">Circuit</span>
<span class="kn">from</span> <span class="nn">pytket.extensions.qiskit</span> <span class="kn">import</span> <span class="n">IBMQBackend</span>
<span class="kn">from</span> <span class="nn">pytket.passes</span> <span class="kn">import</span> <span class="n">PlacementPass</span>
<span class="kn">from</span> <span class="nn">pytket.routing</span> <span class="kn">import</span> <span class="n">LinePlacement</span>
<span class="n">circ</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>

<span class="n">backend</span> <span class="o">=</span> <span class="n">IBMQBackend</span><span class="p">(</span><span class="s2">&quot;ibmq_quito&quot;</span><span class="p">)</span>
<span class="n">place</span> <span class="o">=</span> <span class="n">PlacementPass</span><span class="p">(</span><span class="n">LinePlacement</span><span class="p">(</span><span class="n">backend</span><span class="o">.</span><span class="n">backend_info</span><span class="o">.</span><span class="n">architecture</span><span class="p">))</span>
<span class="n">place</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">circ</span><span class="p">)</span>

<span class="nb">print</span><span class="p">(</span><span class="n">circ</span><span class="o">.</span><span class="n">get_commands</span><span class="p">())</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-none notranslate"><div class="highlight"><pre><span></span>[CX node[2], node[1];, CX node[2], node[3];, CX node[1], node[3];, CX unplaced[0], node[3];, CX node[2], unplaced[0];]
</pre></div>
</div>
</div>
</div>
<p>A custom (partial) placement can be applied by providing the appropriate qubit map.</p>
<div class="jupyter_cell jupyter_container docutils container">
<div class="cell_input code_cell docutils container">
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pytket.circuit</span> <span class="kn">import</span> <span class="n">Circuit</span><span class="p">,</span> <span class="n">Qubit</span><span class="p">,</span> <span class="n">Node</span>
<span class="kn">from</span> <span class="nn">pytket.routing</span> <span class="kn">import</span> <span class="n">Placement</span>
<span class="n">circ</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>

<span class="n">q_map</span> <span class="o">=</span> <span class="p">{</span><span class="n">Qubit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="p">:</span> <span class="n">Node</span><span class="p">(</span><span class="mi">3</span><span class="p">),</span> <span class="n">Qubit</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="p">:</span> <span class="n">Node</span><span class="p">(</span><span class="mi">1</span><span class="p">)}</span>
<span class="n">Placement</span><span class="o">.</span><span class="n">place_with_map</span><span class="p">(</span><span class="n">circ</span><span class="p">,</span> <span class="n">q_map</span><span class="p">)</span>

<span class="nb">print</span><span class="p">(</span><span class="n">circ</span><span class="o">.</span><span class="n">get_commands</span><span class="p">())</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-none notranslate"><div class="highlight"><pre><span></span>[CX node[3], unplaced[0];, CX node[3], node[1];, CX unplaced[0], node[1];, CX unplaced[1], node[1];, CX node[3], unplaced[1];]
</pre></div>
</div>
</div>
</div>
<p>A custom placement may also be defined as a pass (which can then be combined with others to construct a more complex pass).</p>
<div class="jupyter_cell jupyter_container docutils container">
<div class="cell_input code_cell docutils container">
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pytket.circuit</span> <span class="kn">import</span> <span class="n">Circuit</span><span class="p">,</span> <span class="n">Qubit</span><span class="p">,</span> <span class="n">Node</span>
<span class="kn">from</span> <span class="nn">pytket.passes</span> <span class="kn">import</span> <span class="n">RenameQubitsPass</span>
<span class="n">circ</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>

<span class="n">q_map</span> <span class="o">=</span> <span class="p">{</span><span class="n">Qubit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="p">:</span> <span class="n">Qubit</span><span class="p">(</span><span class="s2">&quot;z&quot;</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">Qubit</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="p">:</span> <span class="n">Qubit</span><span class="p">(</span><span class="s2">&quot;z&quot;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)}</span>
<span class="n">rename</span> <span class="o">=</span> <span class="n">RenameQubitsPass</span><span class="p">(</span><span class="n">q_map</span><span class="p">)</span>
<span class="n">rename</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">circ</span><span class="p">)</span>

<span class="nb">print</span><span class="p">(</span><span class="n">circ</span><span class="o">.</span><span class="n">get_commands</span><span class="p">())</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-none notranslate"><div class="highlight"><pre><span></span>[CX z[0], q[1];, CX z[0], z[1];, CX q[1], z[1];, CX q[3], z[1];, CX z[0], q[3];]
</pre></div>
</div>
</div>
</div>
<p>Several heuristics have been implemented for identifying candidate placements. For example, <code class="xref py py-class docutils literal notranslate"><span class="pre">LinePlacement</span></code> will try to identify long paths on the connectivity graph which could be treated as a linear nearest-neighbour system. <code class="xref py py-class docutils literal notranslate"><span class="pre">GraphPlacement</span></code> will try to identify a subgraph isomorphism between the graph of interacting logical qubits (up to some depth into the <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code>) and the connectivity graph of the physical qubits. Then <code class="xref py py-class docutils literal notranslate"><span class="pre">NoiseAwarePlacement</span></code> extends this to break ties in equivalently good graph maps by looking at the error rates of the physical qubits and their couplers. The latter two can be configured using e.g. <code class="xref py py-meth docutils literal notranslate"><span class="pre">GraphPlacement.modify_config()</span></code> to change parameters like how far into the <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> it will look for interacting qubits (trading off time spent searching for the chance to find a better placement).</p>
<div class="jupyter_cell jupyter_container docutils container">
<div class="cell_input code_cell docutils container">
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pytket</span> <span class="kn">import</span> <span class="n">Circuit</span>
<span class="kn">from</span> <span class="nn">pytket.extensions.qiskit</span> <span class="kn">import</span> <span class="n">IBMQBackend</span>
<span class="kn">from</span> <span class="nn">pytket.passes</span> <span class="kn">import</span> <span class="n">PlacementPass</span>
<span class="kn">from</span> <span class="nn">pytket.predicates</span> <span class="kn">import</span> <span class="n">ConnectivityPredicate</span>
<span class="kn">from</span> <span class="nn">pytket.routing</span> <span class="kn">import</span> <span class="n">GraphPlacement</span>
<span class="n">circ</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">)</span>   <span class="c1"># Extra interaction hidden at higher depth than cutoff</span>

<span class="n">backend</span> <span class="o">=</span> <span class="n">IBMQBackend</span><span class="p">(</span><span class="s2">&quot;ibmq_quito&quot;</span><span class="p">)</span>
<span class="n">g_pl</span> <span class="o">=</span> <span class="n">GraphPlacement</span><span class="p">(</span><span class="n">backend</span><span class="o">.</span><span class="n">backend_info</span><span class="o">.</span><span class="n">architecture</span><span class="p">)</span>
<span class="n">connected</span> <span class="o">=</span> <span class="n">ConnectivityPredicate</span><span class="p">(</span><span class="n">backend</span><span class="o">.</span><span class="n">backend_info</span><span class="o">.</span><span class="n">architecture</span><span class="p">)</span>

<span class="n">PlacementPass</span><span class="p">(</span><span class="n">g_pl</span><span class="p">)</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">circ</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">connected</span><span class="o">.</span><span class="n">verify</span><span class="p">(</span><span class="n">circ</span><span class="p">))</span>   <span class="c1"># Imperfect placement because the final CX was not considered</span>

<span class="c1"># Default depth limit is 5, but there is a new interaction at depth 11</span>
<span class="n">g_pl</span><span class="o">.</span><span class="n">modify_config</span><span class="p">(</span><span class="n">depth_limit</span><span class="o">=</span><span class="mi">11</span><span class="p">)</span>

<span class="n">PlacementPass</span><span class="p">(</span><span class="n">g_pl</span><span class="p">)</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">circ</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">connected</span><span class="o">.</span><span class="n">verify</span><span class="p">(</span><span class="n">circ</span><span class="p">))</span>   <span class="c1"># Now have an exact placement</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-none notranslate"><div class="highlight"><pre><span></span>False
True
</pre></div>
</div>
</div>
</div>
</div>
<div class="section" id="routing">
<span id="compiler-routing"></span><h2>Routing<a class="headerlink" href="#routing" title="Permalink to this headline"></a></h2>
<p>The heterogeneity of quantum architectures and limited connectivity of their qubits impose the strict restriction that multi-qubit gates are only allowed between specific pairs of qubits. Given it is far easier to program a high-level operation which is semantically correct and meaningful when assuming full connectivity, a compiler will have to solve this constraint. In general, there won’t be an exact subgraph isomorphism between the graph of interacting logical qubits and the connected physical qubits, so this cannot be solved with placement alone.</p>
<p>One solution here, is to scan through the <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> looking for invalid interactions. Each of these can be solved by either moving the qubits around on the architecture by adding <code class="docutils literal notranslate"><span class="pre">OpType.SWAP</span></code> gates until they are in adjacent locations, or performing a distributed entangling operation using the intervening qubits (such as the “bridged-CX” <code class="docutils literal notranslate"><span class="pre">OpType.BRIDGE</span></code> which uses 4 CX gates and a single shared neighbour). The <cite>routing</cite> procedure in <code class="docutils literal notranslate"><span class="pre">pytket</span></code> takes a placed <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> and inserts gates to reduce non-local operations to sequences of valid local ones.</p>
<div class="jupyter_cell jupyter_container docutils container">
<div class="cell_input code_cell docutils container">
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pytket</span> <span class="kn">import</span> <span class="n">Circuit</span>
<span class="kn">from</span> <span class="nn">pytket.extensions.qiskit</span> <span class="kn">import</span> <span class="n">IBMQBackend</span>
<span class="kn">from</span> <span class="nn">pytket.passes</span> <span class="kn">import</span> <span class="n">PlacementPass</span><span class="p">,</span> <span class="n">RoutingPass</span>
<span class="kn">from</span> <span class="nn">pytket.routing</span> <span class="kn">import</span> <span class="n">GraphPlacement</span>
<span class="n">circ</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
<span class="n">backend</span> <span class="o">=</span> <span class="n">IBMQBackend</span><span class="p">(</span><span class="s2">&quot;ibmq_quito&quot;</span><span class="p">)</span>
<span class="n">PlacementPass</span><span class="p">(</span><span class="n">GraphPlacement</span><span class="p">(</span><span class="n">backend</span><span class="o">.</span><span class="n">backend_info</span><span class="o">.</span><span class="n">architecture</span><span class="p">))</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">circ</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">circ</span><span class="o">.</span><span class="n">get_commands</span><span class="p">())</span>  <span class="c1"># One qubit still unplaced</span>
                            <span class="c1"># node[0] and node[2] are not adjacent</span>

<span class="n">RoutingPass</span><span class="p">(</span><span class="n">backend</span><span class="o">.</span><span class="n">backend_info</span><span class="o">.</span><span class="n">architecture</span><span class="p">)</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">circ</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">circ</span><span class="o">.</span><span class="n">get_commands</span><span class="p">())</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-none notranslate"><div class="highlight"><pre><span></span>[CX node[1], node[0];, CX node[1], node[2];, CX node[0], node[2];, CX unplaced[0], node[2];, CX node[1], unplaced[0];]
[CX node[1], node[0];, CX node[1], node[2];, SWAP node[0], node[1];, CX node[1], node[2];, SWAP node[1], node[3];, CX node[1], node[2];, CX node[0], node[1];]
</pre></div>
</div>
</div>
</div>
<p>As shown here, if a partial placement is used, the routing procedure will allocate the remaining qubits on the fly. We also see that the logical qubits are mapped to different physical qubits at the start and end because of the inserted <code class="docutils literal notranslate"><span class="pre">OpType.SWAP</span></code> gates, such as <code class="docutils literal notranslate"><span class="pre">q[1]</span></code> starting at <code class="docutils literal notranslate"><span class="pre">node[0]</span></code> and ending at <code class="docutils literal notranslate"><span class="pre">node[3]</span></code>.</p>
<p>The heuristics of the routing algorithm also have a selection of hyperparameters which can change how well it performs for each instance, such as how far ahead it will look when considering what is the best pair of qubits to swap or whether a distributed operation would work better. These are outlined in more detail in the API reference.</p>
</div>
<div class="section" id="decomposing-structures">
<h2>Decomposing Structures<a class="headerlink" href="#decomposing-structures" title="Permalink to this headline"></a></h2>
<p>The numerous Box structures in <code class="docutils literal notranslate"><span class="pre">pytket</span></code> provide practical abstractions for high-level operations to assist in <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> construction, but need to be mapped to low-level gates before we can run the <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code>. The <code class="xref py py-class docutils literal notranslate"><span class="pre">DecomposeBoxes</span></code> pass will unwrap any <code class="xref py py-class docutils literal notranslate"><span class="pre">CircBox</span></code>, substituting it for the corresponding <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code>, and decompose others like the <code class="xref py py-class docutils literal notranslate"><span class="pre">Unitary1qBox</span></code> and <code class="xref py py-class docutils literal notranslate"><span class="pre">PauliExpBox</span></code> into efficient templated patterns of gates.</p>
<div class="jupyter_cell jupyter_container docutils container">
<div class="cell_input code_cell docutils container">
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pytket.circuit</span> <span class="kn">import</span> <span class="n">Circuit</span><span class="p">,</span> <span class="n">CircBox</span><span class="p">,</span> <span class="n">PauliExpBox</span>
<span class="kn">from</span> <span class="nn">pytket.passes</span> <span class="kn">import</span> <span class="n">DecomposeBoxes</span>
<span class="kn">from</span> <span class="nn">pytket.pauli</span> <span class="kn">import</span> <span class="n">Pauli</span>
<span class="n">sub</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="n">sub</span><span class="o">.</span><span class="n">CZ</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">T</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">Tdg</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">sub_box</span> <span class="o">=</span> <span class="n">CircBox</span><span class="p">(</span><span class="n">sub</span><span class="p">)</span>
<span class="n">circ</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">Rx</span><span class="p">(</span><span class="mf">0.42</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">add_circbox</span><span class="p">(</span><span class="n">sub_box</span><span class="p">,</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">])</span>
<span class="n">circ</span><span class="o">.</span><span class="n">add_circbox</span><span class="p">(</span><span class="n">sub_box</span><span class="p">,</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">])</span>
<span class="n">circ</span><span class="o">.</span><span class="n">add_pauliexpbox</span><span class="p">(</span><span class="n">PauliExpBox</span><span class="p">([</span><span class="n">Pauli</span><span class="o">.</span><span class="n">X</span><span class="p">,</span> <span class="n">Pauli</span><span class="o">.</span><span class="n">Y</span><span class="p">,</span> <span class="n">Pauli</span><span class="o">.</span><span class="n">Y</span><span class="p">,</span> <span class="n">Pauli</span><span class="o">.</span><span class="n">Y</span><span class="p">],</span> <span class="mf">0.2</span><span class="p">),</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">])</span>

<span class="n">DecomposeBoxes</span><span class="p">()</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">circ</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">circ</span><span class="o">.</span><span class="n">get_commands</span><span class="p">())</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-none notranslate"><div class="highlight"><pre><span></span>[Rx(0.42) q[2];, CX q[2], q[0];, CZ q[0], q[1];, CZ q[2], q[3];, T q[0];, Tdg q[1];, T q[2];, Tdg q[3];, H q[0];, V q[1];, V q[2];, V q[3];, CX q[3], q[2];, CX q[2], q[1];, CX q[1], q[0];, Rz(0.2) q[0];, CX q[1], q[0];, H q[0];, CX q[2], q[1];, Vdg q[1];, CX q[3], q[2];, Vdg q[2];, Vdg q[3];]
</pre></div>
</div>
</div>
</div>
<p>Unwrapping Boxes could introduce arbitrarily complex structures into a <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> which could possibly invalidate almost all <code class="xref py py-class docutils literal notranslate"><span class="pre">Predicate</span></code> s, including <code class="xref py py-class docutils literal notranslate"><span class="pre">GateSetPredicate</span></code>, <code class="xref py py-class docutils literal notranslate"><span class="pre">ConnectivityPredicate</span></code>, and <code class="xref py py-class docutils literal notranslate"><span class="pre">NoMidMeasurePredicate</span></code>. It is hence recommended to apply this early in the compilation procedure, prior to any pass that solves for these constraints.</p>
</div>
<div class="section" id="optimisations">
<h2>Optimisations<a class="headerlink" href="#optimisations" title="Permalink to this headline"></a></h2>
<p>Having covered the primary goal of compilation and reduced our <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> s to a form where they can be run, we find that there are additional techniques we can use to obtain more reliable results by reducing the noise and probability of error. Most <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> optimisations follow the mantra of “fewer expensive resources gives less opportunity for noise to creep in”, whereby if we find an alternative <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> that is observationally equivalent in a perfect noiseless setting but uses fewer resources (gates, time, ancilla qubits) then it is likely to perform better in a noisy context (though not always guaranteed).</p>
<p>If we have two <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> s that are observationally equivalent, we know that replacing one for the other in any context also gives something that is observationally equivalent. The simplest optimisations will take an inefficient pattern, find all matches in the given <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> and replace them by the efficient alternative. A good example from this class of <cite>peephole</cite> optimisations is the <code class="xref py py-class docutils literal notranslate"><span class="pre">RemoveRedundancies</span></code> pass, which looks for a number of easy-to-spot redundant gates, such as zero-parameter rotation gates, gate-inverse pairs, adjacent rotation gates in the same basis, and diagonal rotation gates followed by measurements.</p>
<div class="jupyter_cell jupyter_container docutils container">
<div class="cell_input code_cell docutils container">
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pytket</span> <span class="kn">import</span> <span class="n">Circuit</span><span class="p">,</span> <span class="n">OpType</span>
<span class="kn">from</span> <span class="nn">pytket.passes</span> <span class="kn">import</span> <span class="n">RemoveRedundancies</span>
<span class="n">circ</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">Rx</span><span class="p">(</span><span class="mf">0.92</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">Rx</span><span class="p">(</span><span class="o">-</span><span class="mf">0.18</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>  <span class="c1"># Adjacent Rx gates can be merged</span>
<span class="n">circ</span><span class="o">.</span><span class="n">CZ</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">Ry</span><span class="p">(</span><span class="mf">0.11</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CZ</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>      <span class="c1"># CZ is self-inverse</span>
<span class="n">circ</span><span class="o">.</span><span class="n">add_gate</span><span class="p">(</span><span class="n">OpType</span><span class="o">.</span><span class="n">XXPhase</span><span class="p">,</span> <span class="mf">0.6</span><span class="p">,</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">])</span>
<span class="n">circ</span><span class="o">.</span><span class="n">add_gate</span><span class="p">(</span><span class="n">OpType</span><span class="o">.</span><span class="n">YYPhase</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">])</span>    <span class="c1"># 0-angle rotation does nothing</span>
<span class="n">circ</span><span class="o">.</span><span class="n">add_gate</span><span class="p">(</span><span class="n">OpType</span><span class="o">.</span><span class="n">ZZPhase</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.84</span><span class="p">,</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">])</span>
<span class="n">circ</span><span class="o">.</span><span class="n">Rx</span><span class="p">(</span><span class="mf">0.03</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">Rz</span><span class="p">(</span><span class="o">-</span><span class="mf">0.9</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">measure_all</span><span class="p">()</span>  <span class="c1"># Effect of Rz is eliminated by measurement</span>

<span class="n">RemoveRedundancies</span><span class="p">()</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">circ</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">circ</span><span class="o">.</span><span class="n">get_commands</span><span class="p">())</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-none notranslate"><div class="highlight"><pre><span></span>[Rx(0.74) q[0];, CX q[1], q[2];, Mølmer-Sørensen(0.6) q[0], q[1];, Ry(0.11) q[2];, Measure q[2] --&gt; c[2];, ZZPhase(3.16) q[0], q[1];, Measure q[1] --&gt; c[1];, Rx(0.03) q[0];, Measure q[0] --&gt; c[0];]
</pre></div>
</div>
</div>
</div>
<p>It is understandable to question the relevance of such an optimisation, since a sensible programmer would not intentionally write a <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> with such redundant gates. These are still largely useful because other compiler passes might introduce them, such as routing adding a <code class="docutils literal notranslate"><span class="pre">OpType.SWAP</span></code> gate immediately following a <code class="docutils literal notranslate"><span class="pre">OpType.SWAP</span></code> gate made by the user, or commuting a Z-rotation through the control of a CX which allows it to merge with another Z-rotation on the other side.</p>
<p>Previous iterations of the <code class="xref py py-class docutils literal notranslate"><span class="pre">CliffordSimp</span></code> pass would work in this way as well, looking for specific sequences of Clifford gates where we could reduce the number of two-qubit gates. This has since been generalised to spot these patterns up to gate commutations and changes of basis from single-qubit Clifford rotations.</p>
<div class="jupyter_cell jupyter_container docutils container">
<div class="cell_input code_cell docutils container">
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pytket</span> <span class="kn">import</span> <span class="n">Circuit</span><span class="p">,</span> <span class="n">OpType</span>
<span class="kn">from</span> <span class="nn">pytket.passes</span> <span class="kn">import</span> <span class="n">CliffordSimp</span>
<span class="c1"># A basic inefficient pattern can be reduced by 1 CX</span>
<span class="n">simple</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="n">simple</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">S</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>

<span class="n">CliffordSimp</span><span class="p">()</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">simple</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">simple</span><span class="o">.</span><span class="n">get_commands</span><span class="p">())</span>

<span class="c1"># The same pattern, up to commutation and local Clifford algebra</span>
<span class="nb">complex</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
<span class="nb">complex</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="nb">complex</span><span class="o">.</span><span class="n">Rx</span><span class="p">(</span><span class="mf">0.42</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="nb">complex</span><span class="o">.</span><span class="n">S</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="nb">complex</span><span class="o">.</span><span class="n">add_gate</span><span class="p">(</span><span class="n">OpType</span><span class="o">.</span><span class="n">YYPhase</span><span class="p">,</span> <span class="mf">0.96</span><span class="p">,</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">])</span>  <span class="c1"># Requires 2 CXs to implement</span>
<span class="nb">complex</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>

<span class="n">CliffordSimp</span><span class="p">()</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="nb">complex</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="nb">complex</span><span class="o">.</span><span class="n">get_commands</span><span class="p">())</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-none notranslate"><div class="highlight"><pre><span></span>[CX q[1], q[0];, tk1(0, 0, 0.5) q[0];]
[tk1(0, 0, 0.5) q[0];, tk1(1.92, 3.5, 3.5) q[1];, tk1(0, 0.5, 0) q[2];, CX q[1], q[2];, tk1(0, 1.5, 0.96) q[2];, CX q[1], q[2];, tk1(0, 0.5, 0) q[1];, CX q[0], q[1];, tk1(0.5, 0.5, 0.5) q[1];]
</pre></div>
</div>
</div>
</div>
<p>The next step up in scale has optimisations based on optimal decompositions of subcircuits over <span class="math notranslate nohighlight">\(n\)</span>-qubits, including <code class="xref py py-class docutils literal notranslate"><span class="pre">EulerAngleReduction</span></code> for single-qubit unitary chains (producing three rotations in a choice of axes), and <code class="xref py py-class docutils literal notranslate"><span class="pre">KAKDecomposition</span></code> for two-qubit unitaries (using at most three CXs and some single-qubit gates).</p>
<div class="jupyter_cell jupyter_container docutils container">
<div class="cell_input code_cell docutils container">
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pytket</span> <span class="kn">import</span> <span class="n">Circuit</span><span class="p">,</span> <span class="n">OpType</span>
<span class="kn">from</span> <span class="nn">pytket.passes</span> <span class="kn">import</span> <span class="n">EulerAngleReduction</span><span class="p">,</span> <span class="n">KAKDecomposition</span>
<span class="n">circ</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">CZ</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">Rx</span><span class="p">(</span><span class="mf">0.4</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">Rz</span><span class="p">(</span><span class="mf">0.289</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">Ry</span><span class="p">(</span><span class="o">-</span><span class="mf">0.34</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">Rz</span><span class="p">(</span><span class="mf">0.12</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">Ry</span><span class="p">(</span><span class="o">-</span><span class="mf">0.81</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>

<span class="c1"># Reduce long chain to a triple of Rz, Rx, Rz</span>
<span class="n">EulerAngleReduction</span><span class="p">(</span><span class="n">OpType</span><span class="o">.</span><span class="n">Rz</span><span class="p">,</span> <span class="n">OpType</span><span class="o">.</span><span class="n">Rx</span><span class="p">)</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">circ</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">circ</span><span class="o">.</span><span class="n">get_commands</span><span class="p">())</span>

<span class="n">circ</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">Rx</span><span class="p">(</span><span class="mf">0.3</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">Rz</span><span class="p">(</span><span class="mf">1.5</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">Ry</span><span class="p">(</span><span class="o">-</span><span class="mf">0.94</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">Ry</span><span class="p">(</span><span class="mf">0.37</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>

<span class="c1"># Reduce long 2-qubit subcircuit to at most 3 CXs</span>
<span class="n">KAKDecomposition</span><span class="p">()</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">circ</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">circ</span><span class="o">.</span><span class="n">get_commands</span><span class="p">())</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-none notranslate"><div class="highlight"><pre><span></span>[CZ q[0], q[1];, Rx(0.4) q[0];, Rz(0.289) q[0];, Ry(3.66) q[0];, Rz(0.12) q[0];, Ry(3.19) q[0];, CX q[1], q[0];]
[CX q[0], q[1];, tk1(0, 0.5, 0) q[2];, tk1(0.607193, 0.5, 0) q[1];, CX q[1], q[2];, tk1(3.5, 0.425003, 1) q[1];, tk1(1, 0.5, 0.06) q[2];, CX q[1], q[2];, tk1(1, 0.5, 3.68719) q[1];, tk1(3.5, 0, 0) q[2];, CX q[1], q[0];]
</pre></div>
</div>
</div>
</div>
<p>All of these so far are generic optimisations that work for any application, but only identify local redundancies since they are limited to working up to individual gate commutations. Other techniques instead focus on identifying macroscopic structures in a <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> or convert it entirely into an alternative algebraic representation, and then using the properties of the structures/algebra to find simplifications and resynthesise into basic gates. For example, the <code class="xref py py-class docutils literal notranslate"><span class="pre">PauliSimp</span></code> pass will represent the entire <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> as a sequence of exponentials of Pauli operators, capturing the effects of non-Clifford gates as rotations in a basis determined by the Clifford gates. This abstracts away any redundant information in the Clifford gates entirely, and can be used to merge non-Clifford gates that cannot be brought together from any sequence of commutations, as well as finding efficient Clifford constructions for the basis changes.</p>
<div class="jupyter_cell jupyter_container docutils container">
<div class="cell_input code_cell docutils container">
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pytket</span> <span class="kn">import</span> <span class="n">Circuit</span>
<span class="kn">from</span> <span class="nn">pytket.passes</span> <span class="kn">import</span> <span class="n">PauliSimp</span>
<span class="kn">from</span> <span class="nn">pytket.utils</span> <span class="kn">import</span> <span class="n">Graph</span>
<span class="n">circ</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">Rz</span><span class="p">(</span><span class="mf">0.2</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">Rx</span><span class="p">(</span><span class="mf">0.35</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">V</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">H</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">Rz</span><span class="p">(</span><span class="o">-</span><span class="mf">0.6</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">Vdg</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">H</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">H</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">H</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">Rz</span><span class="p">(</span><span class="mf">0.8</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">H</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">H</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">Rx</span><span class="p">(</span><span class="mf">0.1</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>

<span class="n">PauliSimp</span><span class="p">()</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">circ</span><span class="p">)</span>
<span class="n">Graph</span><span class="p">(</span><span class="n">circ</span><span class="p">)</span><span class="o">.</span><span class="n">get_DAG</span><span class="p">()</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<img alt="_images/manual_compiler_13_0.svg" src="_images/manual_compiler_13_0.svg" /></div>
</div>
<p>This can give great benefits for <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> s where non-Clifford gates are sparse and there is hence a lot of redundancy in the Clifford change-of-basis sections. But if the <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> already has a very efficient usage of Clifford gates, this will be lost when converting to the abstract representation, and so the resynthesis is likely to give less efficient sequences. The large structural changes from abstraction and resynthesis can also make routing harder to perform as the interaction graph of the logical qubits can drastically change. The effectiveness of such optimisations depends on the situation, but can be transformative under the right circumstances.</p>
<p>Some of these optimisation passes have optional parameters to customise the routine slightly. A good example is adapting the <code class="xref py py-class docutils literal notranslate"><span class="pre">PauliSimp</span></code> pass to have a preference for different forms of <code class="docutils literal notranslate"><span class="pre">OpType.CX</span></code> decompositions. Setting the <code class="docutils literal notranslate"><span class="pre">cx_config</span></code> option to <code class="docutils literal notranslate"><span class="pre">CXConfigType.Snake</span></code> (default) will prefer chains of gates where the target of one becomes the control of the next, whereas <code class="docutils literal notranslate"><span class="pre">CXConfigType.Star</span></code> prefers using a single qubit as the control for many gates, and <code class="docutils literal notranslate"><span class="pre">CXConfigType.Tree</span></code> introduces entanglement in a balanced tree form. Each of these has its own benefits and drawbacks that could make it more effective for a particular routine, like <code class="docutils literal notranslate"><span class="pre">CXConfigType.Snake</span></code> giving circuits that are easier to route on linear nearest-neighbour architectures, <code class="docutils literal notranslate"><span class="pre">CXConfigType.Star</span></code> allowing any of the gates to commute through to cancel out with others at the start or end of the sequence, and <code class="docutils literal notranslate"><span class="pre">CXConfigType.Tree</span></code> giving optimal depth on a fully-connected device.</p>
<div class="jupyter_cell jupyter_container docutils container">
<div class="cell_input code_cell docutils container">
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pytket.circuit</span> <span class="kn">import</span> <span class="n">Circuit</span><span class="p">,</span> <span class="n">PauliExpBox</span>
<span class="kn">from</span> <span class="nn">pytket.passes</span> <span class="kn">import</span> <span class="n">PauliSimp</span>
<span class="kn">from</span> <span class="nn">pytket.pauli</span> <span class="kn">import</span> <span class="n">Pauli</span>
<span class="kn">from</span> <span class="nn">pytket.transform</span> <span class="kn">import</span> <span class="n">CXConfigType</span>
<span class="kn">from</span> <span class="nn">pytket.utils</span> <span class="kn">import</span> <span class="n">Graph</span>
<span class="n">circ</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">add_pauliexpbox</span><span class="p">(</span><span class="n">PauliExpBox</span><span class="p">([</span><span class="n">Pauli</span><span class="o">.</span><span class="n">X</span><span class="p">,</span> <span class="n">Pauli</span><span class="o">.</span><span class="n">Y</span><span class="p">,</span> <span class="n">Pauli</span><span class="o">.</span><span class="n">X</span><span class="p">,</span> <span class="n">Pauli</span><span class="o">.</span><span class="n">Z</span><span class="p">,</span> <span class="n">Pauli</span><span class="o">.</span><span class="n">Y</span><span class="p">,</span> <span class="n">Pauli</span><span class="o">.</span><span class="n">X</span><span class="p">,</span> <span class="n">Pauli</span><span class="o">.</span><span class="n">Z</span><span class="p">,</span> <span class="n">Pauli</span><span class="o">.</span><span class="n">Z</span><span class="p">],</span> <span class="mf">0.42</span><span class="p">),</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">])</span>

<span class="n">PauliSimp</span><span class="p">(</span><span class="n">cx_config</span><span class="o">=</span><span class="n">CXConfigType</span><span class="o">.</span><span class="n">Snake</span><span class="p">)</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">circ</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">circ</span><span class="o">.</span><span class="n">get_commands</span><span class="p">())</span>
<span class="n">Graph</span><span class="p">(</span><span class="n">circ</span><span class="p">)</span><span class="o">.</span><span class="n">get_qubit_graph</span><span class="p">()</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-none notranslate"><div class="highlight"><pre><span></span>[H q[0];, V q[1];, H q[2];, V q[4];, H q[5];, CX q[7], q[6];, CX q[6], q[5];, CX q[5], q[4];, CX q[4], q[3];, CX q[3], q[2];, CX q[2], q[1];, CX q[1], q[0];, Rz(0.42) q[0];, CX q[1], q[0];, H q[0];, CX q[2], q[1];, V q[0];, Vdg q[1];, CX q[3], q[2];, S q[0];, V q[1];, H q[2];, CX q[4], q[3];, H q[0];, S q[1];, V q[2];, V q[3];, CX q[5], q[4];, S q[0];, H q[1];, S q[2];, S q[3];, Vdg q[4];, CX q[6], q[5];, S q[1];, H q[2];, H q[3];, V q[4];, H q[5];, CX q[7], q[6];, S q[2];, S q[3];, S q[4];, V q[5];, V q[6];, V q[7];, H q[4];, S q[5];, S q[6];, S q[7];, S q[4];, H q[5];, H q[6];, H q[7];, S q[5];, S q[6];, S q[7];]
</pre></div>
</div>
<img alt="_images/manual_compiler_14_1.svg" src="_images/manual_compiler_14_1.svg" /></div>
</div>
<div class="jupyter_cell jupyter_container docutils container">
<div class="cell_input code_cell docutils container">
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">PauliSimp</span><span class="p">(</span><span class="n">cx_config</span><span class="o">=</span><span class="n">CXConfigType</span><span class="o">.</span><span class="n">Star</span><span class="p">)</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">circ</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">circ</span><span class="o">.</span><span class="n">get_commands</span><span class="p">())</span>
<span class="n">Graph</span><span class="p">(</span><span class="n">circ</span><span class="p">)</span><span class="o">.</span><span class="n">get_qubit_graph</span><span class="p">()</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-none notranslate"><div class="highlight"><pre><span></span>[H q[0];, V q[1];, H q[2];, V q[4];, H q[5];, CX q[7], q[0];, CX q[6], q[0];, CX q[5], q[0];, CX q[4], q[0];, CX q[3], q[0];, CX q[2], q[0];, CX q[1], q[0];, Rz(0.42) q[0];, CX q[1], q[0];, CX q[2], q[0];, Vdg q[1];, CX q[3], q[0];, V q[1];, H q[2];, CX q[4], q[0];, S q[1];, V q[2];, V q[3];, CX q[5], q[0];, H q[1];, S q[2];, S q[3];, Vdg q[4];, CX q[6], q[0];, S q[1];, H q[2];, H q[3];, V q[4];, H q[5];, CX q[7], q[0];, S q[2];, S q[3];, S q[4];, V q[5];, V q[6];, H q[0];, H q[4];, S q[5];, S q[6];, V q[7];, V q[0];, S q[4];, H q[5];, H q[6];, S q[7];, S q[0];, S q[5];, S q[6];, H q[7];, H q[0];, S q[7];, S q[0];]
</pre></div>
</div>
<img alt="_images/manual_compiler_15_1.svg" src="_images/manual_compiler_15_1.svg" /></div>
</div>
<div class="jupyter_cell jupyter_container docutils container">
<div class="cell_input code_cell docutils container">
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">PauliSimp</span><span class="p">(</span><span class="n">cx_config</span><span class="o">=</span><span class="n">CXConfigType</span><span class="o">.</span><span class="n">Tree</span><span class="p">)</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">circ</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">circ</span><span class="o">.</span><span class="n">get_commands</span><span class="p">())</span>
<span class="n">Graph</span><span class="p">(</span><span class="n">circ</span><span class="p">)</span><span class="o">.</span><span class="n">get_qubit_graph</span><span class="p">()</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-none notranslate"><div class="highlight"><pre><span></span>[H q[0];, V q[1];, H q[2];, V q[4];, H q[5];, CX q[7], q[6];, CX q[1], q[0];, CX q[3], q[2];, CX q[5], q[4];, CX q[2], q[0];, CX q[6], q[4];, CX q[4], q[0];, Rz(0.42) q[0];, CX q[4], q[0];, CX q[2], q[0];, CX q[6], q[4];, CX q[1], q[0];, CX q[3], q[2];, CX q[5], q[4];, CX q[7], q[6];, H q[0];, Vdg q[1];, H q[2];, V q[3];, Vdg q[4];, H q[5];, V q[6];, V q[7];, V q[0];, V q[1];, V q[2];, S q[3];, V q[4];, V q[5];, S q[6];, S q[7];, S q[0];, S q[1];, S q[2];, H q[3];, S q[4];, S q[5];, H q[6];, H q[7];, H q[0];, H q[1];, H q[2];, S q[3];, H q[4];, H q[5];, S q[6];, S q[7];, S q[0];, S q[1];, S q[2];, S q[4];, S q[5];]
</pre></div>
</div>
<img alt="_images/manual_compiler_16_1.svg" src="_images/manual_compiler_16_1.svg" /></div>
</div>
</div>
<div class="section" id="combinators">
<h2>Combinators<a class="headerlink" href="#combinators" title="Permalink to this headline"></a></h2>
<p>The passes encountered so far represent elementary, self-contained transformations on <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> s. In practice, we will almost always want to apply sequences of these to combine optimisations with solving for many constraints. The passes in <code class="docutils literal notranslate"><span class="pre">pytket</span></code> have a rudimentary compositional structure to describe generic compilation strategies, with the most basic example being just applying a list of passes in order.</p>
<div class="jupyter_cell jupyter_container docutils container">
<div class="cell_input code_cell docutils container">
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pytket</span> <span class="kn">import</span> <span class="n">Circuit</span><span class="p">,</span> <span class="n">OpType</span>
<span class="kn">from</span> <span class="nn">pytket.passes</span> <span class="kn">import</span> <span class="n">RebaseQuil</span><span class="p">,</span> <span class="n">EulerAngleReduction</span><span class="p">,</span> <span class="n">SequencePass</span>
<span class="n">circ</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">Rx</span><span class="p">(</span><span class="mf">0.3</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">Rz</span><span class="p">(</span><span class="mf">0.8</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">comp</span> <span class="o">=</span> <span class="n">SequencePass</span><span class="p">([</span><span class="n">RebaseQuil</span><span class="p">(),</span> <span class="n">EulerAngleReduction</span><span class="p">(</span><span class="n">OpType</span><span class="o">.</span><span class="n">Rz</span><span class="p">,</span> <span class="n">OpType</span><span class="o">.</span><span class="n">Rx</span><span class="p">)])</span>
<span class="n">comp</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">circ</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">circ</span><span class="o">.</span><span class="n">get_commands</span><span class="p">())</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-none notranslate"><div class="highlight"><pre><span></span>[Rx(3.3) q[1];, Rz(0.5) q[1];, Rx(0.5) q[1];, CZ q[0], q[1];, CZ q[2], q[1];, Rx(0.5) q[1];, Rz(1.3) q[1];]
</pre></div>
</div>
</div>
</div>
<p>When composing optimisation passes, we may find that applying one type of optimisation could open up opportunities for others by, for example, rearranging gates to match the desired template. To make the most of this, it may be beneficial to apply some pass combination repeatedly until no further changes are made, i.e. until we have found and exploited every simplification that we can.</p>
<div class="jupyter_cell jupyter_container docutils container">
<div class="cell_input code_cell docutils container">
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pytket</span> <span class="kn">import</span> <span class="n">Circuit</span>
<span class="kn">from</span> <span class="nn">pytket.passes</span> <span class="kn">import</span> <span class="n">RemoveRedundancies</span><span class="p">,</span> <span class="n">CommuteThroughMultis</span><span class="p">,</span> <span class="n">RepeatPass</span><span class="p">,</span> <span class="n">SequencePass</span>
<span class="n">circ</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span><span class="o">.</span><span class="n">CY</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">Rz</span><span class="p">(</span><span class="mf">0.24</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">Rz</span><span class="p">(</span><span class="mf">0.89</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">CY</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">Rz</span><span class="p">(</span><span class="o">-</span><span class="mf">0.3</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
<span class="n">comp</span> <span class="o">=</span> <span class="n">RepeatPass</span><span class="p">(</span><span class="n">SequencePass</span><span class="p">([</span><span class="n">CommuteThroughMultis</span><span class="p">(),</span> <span class="n">RemoveRedundancies</span><span class="p">()]))</span>
<span class="n">comp</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">circ</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">circ</span><span class="o">.</span><span class="n">get_commands</span><span class="p">())</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-none notranslate"><div class="highlight"><pre><span></span>[Rz(0.24) q[0];, Rz(0.89) q[1];, Rz(3.7) q[2];]
</pre></div>
</div>
</div>
</div>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>This looping mechanism does not directly compare the <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> to its old state from the previous iteration, instead checking if any of the passes within the loop body claimed they performed any rewrite. Some sequences of passes will do and undo some changes to the <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code>, giving no net effect but nonetheless causing the loop to repeat. This can lead to infinite loops if used in such a way. Some passes where the <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> is converted to another form and back again (e.g. <code class="xref py py-class docutils literal notranslate"><span class="pre">PauliSimp</span></code>) will always report that a change took place. We recommend testing any looping passes thoroughly to check for termination.</p>
</div>
<p>Increased termination safety can be given by only repeating whilst some easy-to-check metric (such as number of gates or depth) decreases. For example, we may want to try to minimise the number of <code class="docutils literal notranslate"><span class="pre">OpType.CX</span></code> gates since these will tend to be very slow and noisy on a lot of devices.</p>
<div class="jupyter_cell jupyter_container docutils container">
<div class="cell_input code_cell docutils container">
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pytket</span> <span class="kn">import</span> <span class="n">Circuit</span><span class="p">,</span> <span class="n">OpType</span>
<span class="kn">from</span> <span class="nn">pytket.passes</span> <span class="kn">import</span> <span class="n">RemoveRedundancies</span><span class="p">,</span> <span class="n">CommuteThroughMultis</span><span class="p">,</span> <span class="n">RepeatWithMetricPass</span><span class="p">,</span> <span class="n">SequencePass</span>
<span class="n">circ</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span><span class="o">.</span><span class="n">CY</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">Rz</span><span class="p">(</span><span class="mf">0.24</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">Rz</span><span class="p">(</span><span class="mf">0.89</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">CY</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">Rz</span><span class="p">(</span><span class="o">-</span><span class="mf">0.3</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
<span class="n">cost</span> <span class="o">=</span> <span class="k">lambda</span> <span class="n">c</span> <span class="p">:</span> <span class="n">c</span><span class="o">.</span><span class="n">n_gates_of_type</span><span class="p">(</span><span class="n">OpType</span><span class="o">.</span><span class="n">CX</span><span class="p">)</span>
<span class="n">comp</span> <span class="o">=</span> <span class="n">RepeatWithMetricPass</span><span class="p">(</span><span class="n">SequencePass</span><span class="p">([</span><span class="n">CommuteThroughMultis</span><span class="p">(),</span> <span class="n">RemoveRedundancies</span><span class="p">()]),</span> <span class="n">cost</span><span class="p">)</span>
<span class="n">comp</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">circ</span><span class="p">)</span>            <span class="c1"># Stops earlier than before, since removing CYs doesn&#39;t change the number of CXs</span>
<span class="nb">print</span><span class="p">(</span><span class="n">circ</span><span class="o">.</span><span class="n">get_commands</span><span class="p">())</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-none notranslate"><div class="highlight"><pre><span></span>[Rz(0.24) q[0];, Rz(0.89) q[1];, CX q[2], q[3];, Rz(3.7) q[2];, CX q[2], q[3];]
</pre></div>
</div>
</div>
</div>
<p>We mentioned earlier that each pass has a set of pre-conditions and post-conditions expressed via <code class="xref py py-class docutils literal notranslate"><span class="pre">Predicate</span></code> s. We may find that applying one pass invalidates the pre-conditions of a later pass, meaning it may hit an error when applied to a <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code>. For example, the <code class="xref py py-class docutils literal notranslate"><span class="pre">KAKDecomposition</span></code> optimisation method can only operate on <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> s with a specific gate set which doesn’t allow for any gates on more than 2 qubits, so when <code class="xref py py-class docutils literal notranslate"><span class="pre">RoutingPass</span></code> can introduce <code class="docutils literal notranslate"><span class="pre">OpType.BRIDGE</span></code> gates over 3 qubits, this could cause an error when trying to apply <code class="xref py py-class docutils literal notranslate"><span class="pre">KAKDecomposition</span></code>. When using combinators like <code class="xref py py-class docutils literal notranslate"><span class="pre">SequencePass</span></code> and <code class="xref py py-class docutils literal notranslate"><span class="pre">RepeatPass</span></code>, <code class="docutils literal notranslate"><span class="pre">pytket</span></code> checks that the passes are safe to compose, in the sense that former passes do not invalidate pre-conditions of the latter passes. This procedure uses a basic form of Hoare logic to identify new pre- and post-conditions for the combined pass and identify whether it is still satisfiable.</p>
<p>A special mention here goes to the <code class="xref py py-class docutils literal notranslate"><span class="pre">DecomposeBoxes</span></code> pass. Because the Box structures could potentially contain arbitrary sequences of gates, there is no guarantee that expanding them will yield a <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> that satisfies <cite>any</cite> <code class="xref py py-class docutils literal notranslate"><span class="pre">Predicate</span></code>. Since it has potential to invalidate the pre-conditions of any subsequent pass, composing it with anything else <cite>will</cite> generate such an error.</p>
<div class="jupyter_cell jupyter_container docutils container">
<div class="cell_input code_cell docutils container">
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pytket.passes</span> <span class="kn">import</span> <span class="n">DecomposeBoxes</span><span class="p">,</span> <span class="n">PauliSimp</span><span class="p">,</span> <span class="n">SequencePass</span>
<span class="c1"># PauliSimp requires a specific gateset and no conditional gates</span>
<span class="c1"># or mid-circuit measurement, so this will raise an exception</span>
<span class="n">comp</span> <span class="o">=</span> <span class="n">SequencePass</span><span class="p">([</span><span class="n">DecomposeBoxes</span><span class="p">(),</span> <span class="n">PauliSimp</span><span class="p">()])</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output traceback highlight-ipythontb notranslate"><div class="highlight"><pre><span></span><span class="gt">---------------------------------------------------------------------------</span>
<span class="ne">RuntimeError</span><span class="g g-Whitespace">                              </span>Traceback (most recent call last)
<span class="o">&lt;</span><span class="n">ipython</span><span class="o">-</span><span class="nb">input</span><span class="o">-</span><span class="mi">17</span><span class="o">-</span><span class="n">e455c605f47a</span><span class="o">&gt;</span> <span class="ow">in</span> <span class="o">&lt;</span><span class="n">module</span><span class="o">&gt;</span>
<span class="g g-Whitespace">      </span><span class="mi">2</span> <span class="c1"># PauliSimp requires a specific gateset and no conditional gates</span>
<span class="g g-Whitespace">      </span><span class="mi">3</span> <span class="c1"># or mid-circuit measurement, so this will raise an exception</span>
<span class="ne">----&gt; </span><span class="mi">4</span> <span class="n">comp</span> <span class="o">=</span> <span class="n">SequencePass</span><span class="p">([</span><span class="n">DecomposeBoxes</span><span class="p">(),</span> <span class="n">PauliSimp</span><span class="p">()])</span>

<span class="ne">RuntimeError</span>: Cannot compose these Compiler Passes due to mismatching Predicates of type: GateSetPredicate
</pre></div>
</div>
</div>
</div>
</div>
<div class="section" id="predefined-sequences">
<h2>Predefined Sequences<a class="headerlink" href="#predefined-sequences" title="Permalink to this headline"></a></h2>
<p>Knowing what sequences of compiler passes to apply for maximal performance is often a very hard problem and can require a lot of experimentation and intuition to predict reliably. Fortunately, there are often common patterns that are applicable to virtually any scenario, for which <code class="docutils literal notranslate"><span class="pre">pytket</span></code> provides some predefined sequences.</p>
<p>In practice, peephole and structure-preserving optimisations are almost always stictly beneficial to apply, or at least will never increase the size of the <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code>. The <code class="xref py py-class docutils literal notranslate"><span class="pre">FullPeepholeOptimise</span></code> sequence is a combination of <code class="xref py py-class docutils literal notranslate"><span class="pre">CliffordSimp</span></code>, <code class="xref py py-class docutils literal notranslate"><span class="pre">RemoveRedundancies</span></code>, <code class="xref py py-class docutils literal notranslate"><span class="pre">CommuteThroughMultis</span></code>, <code class="xref py py-class docutils literal notranslate"><span class="pre">KAKDecomposition</span></code>, and <code class="xref py py-class docutils literal notranslate"><span class="pre">EulerAngleReduction</span></code>, and provides a one-size-approximately-fits-all “kitchen sink” solution to <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> optimisation. This assumes a universal quantum computer, so will not generally preserve gateset, connectivity, etc.</p>
<p>When targeting a heterogeneous device architecture, solving this constraint in its entirety will generally require both placement and subsequent routing. <code class="xref py py-class docutils literal notranslate"><span class="pre">DefaultMappingPass</span></code> simply combines these to apply the <code class="xref py py-class docutils literal notranslate"><span class="pre">GraphPlacement</span></code> strategy and solve any remaining invalid multi-qubit operations. This is taken a step further with <code class="xref py py-class docutils literal notranslate"><span class="pre">CXMappingPass</span></code> which also decomposes the introduced <code class="docutils literal notranslate"><span class="pre">OpType.SWAP</span></code> and <code class="docutils literal notranslate"><span class="pre">OpType.BRIDGE</span></code> gates into elementary <code class="docutils literal notranslate"><span class="pre">OpType.CX</span></code> gates.</p>
<p>After solving for the device connectivity, we then need to restrict what optimisations we can apply to those that won’t invalidate this. The set of <code class="xref py py-class docutils literal notranslate"><span class="pre">SynthesiseX</span></code> passes combine light optimisations that preserve the qubit connectivity and target a specific final gate set (e.g. <code class="xref py py-class docutils literal notranslate"><span class="pre">SynthesiseTket</span></code> guarantees the output is in the gateset of <code class="docutils literal notranslate"><span class="pre">OpType.CX</span></code>, <code class="docutils literal notranslate"><span class="pre">OpType.TK1</span></code>, and <code class="docutils literal notranslate"><span class="pre">OpType.Measure</span></code>). In general, this will not reduce the size of a <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> as much as <code class="xref py py-class docutils literal notranslate"><span class="pre">FullPeepholeOptimise</span></code>, but has the benefit of removing some redundancies introduced by routing without invalidating it.</p>
<div class="jupyter_cell jupyter_container docutils container">
<div class="cell_input code_cell docutils container">
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pytket</span> <span class="kn">import</span> <span class="n">Circuit</span><span class="p">,</span> <span class="n">OpType</span>
<span class="kn">from</span> <span class="nn">pytket.extensions.qiskit</span> <span class="kn">import</span> <span class="n">IBMQBackend</span>
<span class="kn">from</span> <span class="nn">pytket.passes</span> <span class="kn">import</span> <span class="n">FullPeepholeOptimise</span><span class="p">,</span> <span class="n">DefaultMappingPass</span><span class="p">,</span> <span class="n">SynthesiseTket</span><span class="p">,</span> <span class="n">RebaseTket</span>
<span class="n">circ</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">CZ</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">CZ</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CZ</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>

<span class="n">RebaseTket</span><span class="p">()</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">circ</span><span class="p">)</span>     <span class="c1"># Get number of 2qb gates by converting all to CX</span>
<span class="nb">print</span><span class="p">(</span><span class="n">circ</span><span class="o">.</span><span class="n">n_gates_of_type</span><span class="p">(</span><span class="n">OpType</span><span class="o">.</span><span class="n">CX</span><span class="p">))</span>

<span class="n">FullPeepholeOptimise</span><span class="p">()</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">circ</span><span class="p">)</span>      <span class="c1"># Freely rewrite circuit</span>
<span class="nb">print</span><span class="p">(</span><span class="n">circ</span><span class="o">.</span><span class="n">n_gates_of_type</span><span class="p">(</span><span class="n">OpType</span><span class="o">.</span><span class="n">CX</span><span class="p">))</span>

<span class="n">backend</span> <span class="o">=</span> <span class="n">IBMQBackend</span><span class="p">(</span><span class="s2">&quot;ibmq_quito&quot;</span><span class="p">)</span>
<span class="n">DefaultMappingPass</span><span class="p">(</span><span class="n">backend</span><span class="o">.</span><span class="n">backend_info</span><span class="o">.</span><span class="n">architecture</span><span class="p">)</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">circ</span><span class="p">)</span>
<span class="n">RebaseTket</span><span class="p">()</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">circ</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">circ</span><span class="o">.</span><span class="n">n_gates_of_type</span><span class="p">(</span><span class="n">OpType</span><span class="o">.</span><span class="n">CX</span><span class="p">))</span>  <span class="c1"># Routing adds gates</span>
<span class="nb">print</span><span class="p">(</span><span class="n">circ</span><span class="o">.</span><span class="n">get_commands</span><span class="p">())</span>

<span class="n">SynthesiseTket</span><span class="p">()</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">circ</span><span class="p">)</span>            <span class="c1"># Some added gates may be redundant</span>
<span class="nb">print</span><span class="p">(</span><span class="n">circ</span><span class="o">.</span><span class="n">n_gates_of_type</span><span class="p">(</span><span class="n">OpType</span><span class="o">.</span><span class="n">CX</span><span class="p">))</span>  <span class="c1"># But not in this case</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-none notranslate"><div class="highlight"><pre><span></span>9
6
9
[tk1(0, 0, 1.5) node[0];, tk1(0, 0, 1.5) node[1];, tk1(0, 0, 1.5) node[2];, tk1(0, 0, 1.5) node[3];, CX node[1], node[0];, tk1(0, 0, 0.5) node[0];, CX node[1], node[2];, CX node[1], node[3];, tk1(0, 0, 0.5) node[2];, tk1(0, 0, 0.5) node[3];, CX node[3], node[4];, CX node[1], node[3];, CX node[3], node[4];, CX node[4], node[3];, CX node[3], node[4];, CX node[3], node[1];]
9
</pre></div>
</div>
</div>
</div>
<p>Also in this category, we have the <code class="xref py py-meth docutils literal notranslate"><span class="pre">Backend.default_compilation_pass()</span></code> which is run by <code class="xref py py-meth docutils literal notranslate"><span class="pre">Backend.get_compiled_circuit()</span></code>. These give a recommended compiler pass to solve the <code class="xref py py-class docutils literal notranslate"><span class="pre">Backend</span></code> ‘s constraints with a choice of optimisation levels.</p>
<table class="docutils align-default">
<colgroup>
<col style="width: 15%" />
<col style="width: 85%" />
</colgroup>
<thead>
<tr class="row-odd"><th class="head"><p>Optimisation level</p></th>
<th class="head"><p>Description</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td><p>0</p></td>
<td><p>Just solves the constraints as simply as possible. No optimisation.</p></td>
</tr>
<tr class="row-odd"><td><p>1</p></td>
<td><p>Adds basic optimisations (those covered by the <code class="xref py py-meth docutils literal notranslate"><span class="pre">SynthesiseX()</span></code> passes) for efficient compilation.</p></td>
</tr>
<tr class="row-even"><td><p>2</p></td>
<td><p>Extends to more intensive optimisations (those covered by the <code class="xref py py-meth docutils literal notranslate"><span class="pre">FullPeepholeOptimise()</span></code> pass).</p></td>
</tr>
</tbody>
</table>
<div class="jupyter_cell jupyter_container docutils container">
<div class="cell_input code_cell docutils container">
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pytket</span> <span class="kn">import</span> <span class="n">Circuit</span><span class="p">,</span> <span class="n">OpType</span>
<span class="kn">from</span> <span class="nn">pytket.extensions.qiskit</span> <span class="kn">import</span> <span class="n">AerBackend</span>
<span class="n">circ</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">CZ</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">H</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">Rx</span><span class="p">(</span><span class="mf">0.42</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">S</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">add_gate</span><span class="p">(</span><span class="n">OpType</span><span class="o">.</span><span class="n">YYPhase</span><span class="p">,</span> <span class="mf">0.96</span><span class="p">,</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">])</span>
<span class="n">circ</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">measure_all</span><span class="p">()</span>
<span class="n">b</span> <span class="o">=</span> <span class="n">AerBackend</span><span class="p">()</span>
<span class="k">for</span> <span class="n">ol</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">3</span><span class="p">):</span>
    <span class="n">test</span> <span class="o">=</span> <span class="n">circ</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
    <span class="n">b</span><span class="o">.</span><span class="n">default_compilation_pass</span><span class="p">(</span><span class="n">ol</span><span class="p">)</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">test</span><span class="p">)</span>
    <span class="k">assert</span> <span class="n">b</span><span class="o">.</span><span class="n">valid_circuit</span><span class="p">(</span><span class="n">test</span><span class="p">)</span>
    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Optimisation level&quot;</span><span class="p">,</span> <span class="n">ol</span><span class="p">)</span>
    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Gates&quot;</span><span class="p">,</span> <span class="n">test</span><span class="o">.</span><span class="n">n_gates</span><span class="p">)</span>
    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;CXs&quot;</span><span class="p">,</span> <span class="n">test</span><span class="o">.</span><span class="n">n_gates_of_type</span><span class="p">(</span><span class="n">OpType</span><span class="o">.</span><span class="n">CX</span><span class="p">))</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-none notranslate"><div class="highlight"><pre><span></span>Optimisation level 0
Gates 9
CXs 1
Optimisation level 1
Gates 13
CXs 4
Optimisation level 2
Gates 12
CXs 3
</pre></div>
</div>
</div>
</div>
</div>
<div class="section" id="guidance-for-combining-passes">
<h2>Guidance for Combining Passes<a class="headerlink" href="#guidance-for-combining-passes" title="Permalink to this headline"></a></h2>
<p>We find that the most powerful optimisation techniques (those that have the potential to reduce <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> size the most for some class of <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> s) tend to have fewer guarantees on the structure of the output, requiring a universal quantum computer with the ability to perform any gates on any qubits. It is recommended to apply these early on in compilation.</p>
<p>The passes to solve some device constraints might invalidate others: for example, the <code class="xref py py-class docutils literal notranslate"><span class="pre">RoutingPass</span></code> generally invalidates <code class="xref py py-class docutils literal notranslate"><span class="pre">NoMidMeasurePredicate</span></code> and <code class="xref py py-class docutils literal notranslate"><span class="pre">GateSetPredicate</span></code>. Therefore, the order in which these are solved should be chosen with care.</p>
<p>For most standard use cases, we recommend starting with <code class="xref py py-class docutils literal notranslate"><span class="pre">DecomposeBoxes</span></code> to reduce the <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> down to primitive gates, followed by strong optimisation passes like <code class="xref py py-class docutils literal notranslate"><span class="pre">PauliSimp</span></code> (when appropriate for the types of <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> s being considered) and <code class="xref py py-class docutils literal notranslate"><span class="pre">FullPeepholeOptimise</span></code> to eliminate a large number of redundant operations. Then start to solve some more device constraints with some choice of placement and routing strategy, followed by <code class="xref py py-class docutils literal notranslate"><span class="pre">DelayMeasures</span></code> to push measurements back through any introduced <code class="docutils literal notranslate"><span class="pre">OpType.SWAP</span></code> or <code class="docutils literal notranslate"><span class="pre">OpType.BRIDGE</span></code> gates, and then finally rebase to the desired gate set. The <code class="xref py py-meth docutils literal notranslate"><span class="pre">Backend.default_compilation_pass()</span></code> definitions can replace this sequence from placement onwards for simplicity. Minor optimisations could also be inserted between successive steps to tidy up any redundancies introduced, as long as they preserve the solved constraints.</p>
</div>
<div class="section" id="initial-and-final-maps">
<h2>Initial and Final Maps<a class="headerlink" href="#initial-and-final-maps" title="Permalink to this headline"></a></h2>
<p><code class="xref py py-class docutils literal notranslate"><span class="pre">PlacementPass</span></code> modifies the set of qubits used in the <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> from the logical names used during construction to the names of the physical addresses on the <code class="xref py py-class docutils literal notranslate"><span class="pre">Backend</span></code>, so the logical qubit names wiil no longer exist within the <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> by design. Knowing the map between the logical qubits and the chosen physical qubits is necessary for understanding the choice of placement, interpreting the final state from a naive simulator, identifying which physical qubits each measurement was made on for error mitigation, and appending additional gates to the logical qubits after applying the pass.</p>
<p>Other passes like <code class="xref py py-class docutils literal notranslate"><span class="pre">RoutingPass</span></code> and <code class="xref py py-class docutils literal notranslate"><span class="pre">CliffordSimp</span></code> can introduce (explicit or implicit) permutations of the logical qubits in the middle of a <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code>, meaning a logical qubit may exist on a different physical qubit at the start of the <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> compared to the end.</p>
<p>We can wrap up a <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> in a <code class="xref py py-class docutils literal notranslate"><span class="pre">CompilationUnit</span></code> to allow us to track any changes to the locations of the logical qubits when passes are applied. The <code class="xref py py-attr docutils literal notranslate"><span class="pre">CompilationUnit.initial_map</span></code> is a dictionary mapping the original <code class="xref py py-class docutils literal notranslate"><span class="pre">UnitID</span></code> s to the corresponding <code class="xref py py-class docutils literal notranslate"><span class="pre">UnitID</span></code> used in <code class="xref py py-attr docutils literal notranslate"><span class="pre">CompilationUnit.circuit</span></code>, and similarly <code class="xref py py-attr docutils literal notranslate"><span class="pre">CompilationUnit.final_map</span></code> for outputs. Applying <code class="xref py py-meth docutils literal notranslate"><span class="pre">BasePass.apply()</span></code> to a <code class="xref py py-class docutils literal notranslate"><span class="pre">CompilationUnit</span></code> will apply the transformation to the underlying <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> and track the changes to the initial and final maps.</p>
<div class="jupyter_cell jupyter_container docutils container">
<div class="cell_input code_cell docutils container">
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pytket</span> <span class="kn">import</span> <span class="n">Circuit</span>
<span class="kn">from</span> <span class="nn">pytket.extensions.qiskit</span> <span class="kn">import</span> <span class="n">IBMQBackend</span>
<span class="kn">from</span> <span class="nn">pytket.passes</span> <span class="kn">import</span> <span class="n">DefaultMappingPass</span>
<span class="kn">from</span> <span class="nn">pytket.predicates</span> <span class="kn">import</span> <span class="n">CompilationUnit</span>
<span class="n">circ</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">5</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">4</span><span class="p">)</span><span class="o">.</span><span class="n">measure_all</span><span class="p">()</span>
<span class="n">backend</span> <span class="o">=</span> <span class="n">IBMQBackend</span><span class="p">(</span><span class="s2">&quot;ibmq_quito&quot;</span><span class="p">)</span>
<span class="n">cu</span> <span class="o">=</span> <span class="n">CompilationUnit</span><span class="p">(</span><span class="n">circ</span><span class="p">)</span>
<span class="n">DefaultMappingPass</span><span class="p">(</span><span class="n">backend</span><span class="o">.</span><span class="n">backend_info</span><span class="o">.</span><span class="n">architecture</span><span class="p">)</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">cu</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">cu</span><span class="o">.</span><span class="n">circuit</span><span class="o">.</span><span class="n">get_commands</span><span class="p">())</span>
<span class="nb">print</span><span class="p">(</span><span class="n">cu</span><span class="o">.</span><span class="n">initial_map</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">cu</span><span class="o">.</span><span class="n">final_map</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-none notranslate"><div class="highlight"><pre><span></span>[CX node[1], node[0];, Measure node[0] --&gt; c[1];, CX node[1], node[2];, Measure node[2] --&gt; c[2];, CX node[1], node[3];, Measure node[3] --&gt; c[3];, SWAP node[1], node[3];, CX node[3], node[4];, Measure node[3] --&gt; c[0];, Measure node[4] --&gt; c[4];]
{c[0]: c[0], c[1]: c[1], c[2]: c[2], c[3]: c[3], c[4]: c[4], q[0]: node[1], q[1]: node[0], q[2]: node[2], q[3]: node[3], q[4]: node[4]}
{c[0]: c[0], c[1]: c[1], c[2]: c[2], c[3]: c[3], c[4]: c[4], q[0]: node[3], q[1]: node[0], q[2]: node[2], q[3]: node[1], q[4]: node[4]}
</pre></div>
</div>
</div>
</div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>No passes currently rename or swap classical data, but the classical bits are included in these maps for completeness.</p>
</div>
</div>
<div class="section" id="advanced-topics">
<h2>Advanced Topics<a class="headerlink" href="#advanced-topics" title="Permalink to this headline"></a></h2>
<div class="section" id="compiling-symbolic-circuits">
<h3>Compiling Symbolic Circuits<a class="headerlink" href="#compiling-symbolic-circuits" title="Permalink to this headline"></a></h3>
<p>For variational algorithms, the prominent benefit of defining a <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> symbolically and only instantiating it with concrete values when needed is that the compilation procedure would only need to be performed once. By saving time here we can cut down the overall time for an experiment; we could invest the time saved into applying more expensive optimisations on the <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> to reduce the impact of noise further.</p>
<div class="jupyter_cell jupyter_container docutils container">
<div class="cell_input code_cell docutils container">
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pytket</span> <span class="kn">import</span> <span class="n">Circuit</span><span class="p">,</span> <span class="n">Qubit</span>
<span class="kn">from</span> <span class="nn">pytket.extensions.qiskit</span> <span class="kn">import</span> <span class="n">AerStateBackend</span>
<span class="kn">from</span> <span class="nn">pytket.pauli</span> <span class="kn">import</span> <span class="n">Pauli</span><span class="p">,</span> <span class="n">QubitPauliString</span>
<span class="kn">from</span> <span class="nn">pytket.utils.operators</span> <span class="kn">import</span> <span class="n">QubitPauliOperator</span>
<span class="kn">from</span> <span class="nn">sympy</span> <span class="kn">import</span> <span class="n">symbols</span>
<span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="n">symbols</span><span class="p">(</span><span class="s2">&quot;a b&quot;</span><span class="p">)</span>
<span class="n">circ</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">Ry</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">Ry</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">Rz</span><span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">circ</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">xx</span> <span class="o">=</span> <span class="n">QubitPauliString</span><span class="p">({</span><span class="n">Qubit</span><span class="p">(</span><span class="mi">0</span><span class="p">):</span><span class="n">Pauli</span><span class="o">.</span><span class="n">X</span><span class="p">,</span> <span class="n">Qubit</span><span class="p">(</span><span class="mi">1</span><span class="p">):</span><span class="n">Pauli</span><span class="o">.</span><span class="n">X</span><span class="p">})</span>
<span class="n">op</span> <span class="o">=</span> <span class="n">QubitPauliOperator</span><span class="p">({</span><span class="n">xx</span> <span class="p">:</span> <span class="mf">1.5</span><span class="p">})</span>

<span class="n">backend</span> <span class="o">=</span> <span class="n">AerStateBackend</span><span class="p">()</span>
<span class="n">circ</span> <span class="o">=</span> <span class="n">backend</span><span class="o">.</span><span class="n">get_compiled_circuit</span><span class="p">(</span><span class="n">circ</span><span class="p">)</span>   <span class="c1"># Compile once outside of the objective function</span>

<span class="k">def</span> <span class="nf">objective</span><span class="p">(</span><span class="n">params</span><span class="p">):</span>
    <span class="n">state</span> <span class="o">=</span> <span class="n">circ</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
    <span class="n">state</span><span class="o">.</span><span class="n">symbol_substitution</span><span class="p">({</span><span class="n">a</span> <span class="p">:</span> <span class="n">params</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">b</span> <span class="p">:</span> <span class="n">params</span><span class="p">[</span><span class="mi">1</span><span class="p">]})</span>
    <span class="n">handle</span> <span class="o">=</span> <span class="n">backend</span><span class="o">.</span><span class="n">process_circuit</span><span class="p">(</span><span class="n">state</span><span class="p">)</span> <span class="c1"># No need to compile again</span>
    <span class="n">vec</span> <span class="o">=</span> <span class="n">backend</span><span class="o">.</span><span class="n">get_result</span><span class="p">(</span><span class="n">handle</span><span class="p">)</span><span class="o">.</span><span class="n">get_state</span><span class="p">()</span>
    <span class="k">return</span> <span class="n">op</span><span class="o">.</span><span class="n">state_expectation</span><span class="p">(</span><span class="n">vec</span><span class="p">)</span>

<span class="nb">print</span><span class="p">(</span><span class="n">objective</span><span class="p">([</span><span class="mf">0.25</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">]))</span>
<span class="nb">print</span><span class="p">(</span><span class="n">objective</span><span class="p">([</span><span class="mf">0.5</span><span class="p">,</span> <span class="mi">0</span><span class="p">]))</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-none notranslate"><div class="highlight"><pre><span></span>(0.7499999999999999+0j)
(1.5+0j)
</pre></div>
</div>
</div>
</div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Every <code class="xref py py-class docutils literal notranslate"><span class="pre">Backend</span></code> requires <code class="xref py py-class docutils literal notranslate"><span class="pre">NoSymbolsPredicate</span></code>, so it is necessary to instantiate all symbols before running a <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code>.</p>
</div>
</div>
<div class="section" id="partial-compilation">
<h3>Partial Compilation<a class="headerlink" href="#partial-compilation" title="Permalink to this headline"></a></h3>
<p>A common pattern across expectation value and tomography experiments is to run many <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> s that have large identical regions, such as a single state preparation with many different measurements. We can further speed up the overall compilation time by splitting up the state preparation from the measurements, compiling each subcircuit only once, and composing together at the end.</p>
<p>The main technical consideration here is that the compiler will only have the freedom to identify good placements for the first subcircuit to be run. This means that the state preparation should be compiled first, and the placement for the measurements is given by the final map in order to compose well.</p>
<p>Once compiled, we can use <code class="xref py py-meth docutils literal notranslate"><span class="pre">Backend.process_circuits()</span></code> to submit several circuits at once for execution on the backend. The circuits to be executed are passed as list. If the backend is shot-based, the number of shots can be passed using the <cite>n_shots</cite> parameter, which can be a single integer or a list of integers of the same length as the list of circuits to be executed. In the following example, 4000 shots are measured for the first circuit and 2000 for the second.</p>
<div class="jupyter_cell jupyter_container docutils container">
<div class="cell_input code_cell docutils container">
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pytket</span> <span class="kn">import</span> <span class="n">Circuit</span><span class="p">,</span> <span class="n">OpType</span>
<span class="kn">from</span> <span class="nn">pytket.extensions.qiskit</span> <span class="kn">import</span> <span class="n">IBMQBackend</span>
<span class="kn">from</span> <span class="nn">pytket.predicates</span> <span class="kn">import</span> <span class="n">CompilationUnit</span>
<span class="kn">from</span> <span class="nn">pytket.routing</span> <span class="kn">import</span> <span class="n">Placement</span>
<span class="n">state_prep</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
<span class="n">state_prep</span><span class="o">.</span><span class="n">H</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="n">state_prep</span><span class="o">.</span><span class="n">add_gate</span><span class="p">(</span><span class="n">OpType</span><span class="o">.</span><span class="n">CnRy</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">,</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">])</span>
<span class="n">state_prep</span><span class="o">.</span><span class="n">add_gate</span><span class="p">(</span><span class="n">OpType</span><span class="o">.</span><span class="n">CnRy</span><span class="p">,</span> <span class="mf">0.2</span><span class="p">,</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">])</span>
<span class="n">state_prep</span><span class="o">.</span><span class="n">add_gate</span><span class="p">(</span><span class="n">OpType</span><span class="o">.</span><span class="n">CnRy</span><span class="p">,</span> <span class="mf">0.3</span><span class="p">,</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">])</span>
<span class="n">measure0</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="mi">4</span><span class="p">)</span>
<span class="n">measure0</span><span class="o">.</span><span class="n">H</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">H</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span><span class="o">.</span><span class="n">measure_all</span><span class="p">()</span>
<span class="n">measure1</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="mi">4</span><span class="p">)</span>
<span class="n">measure1</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">measure_all</span><span class="p">()</span>

<span class="n">backend</span> <span class="o">=</span> <span class="n">IBMQBackend</span><span class="p">(</span><span class="s2">&quot;ibmq_quito&quot;</span><span class="p">)</span>
<span class="n">cu</span> <span class="o">=</span> <span class="n">CompilationUnit</span><span class="p">(</span><span class="n">state_prep</span><span class="p">)</span>
<span class="n">backend</span><span class="o">.</span><span class="n">default_compilation_pass</span><span class="p">()</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">cu</span><span class="p">)</span>
<span class="n">Placement</span><span class="o">.</span><span class="n">place_with_map</span><span class="p">(</span><span class="n">measure0</span><span class="p">,</span> <span class="n">cu</span><span class="o">.</span><span class="n">final_map</span><span class="p">)</span>
<span class="n">Placement</span><span class="o">.</span><span class="n">place_with_map</span><span class="p">(</span><span class="n">measure1</span><span class="p">,</span> <span class="n">cu</span><span class="o">.</span><span class="n">final_map</span><span class="p">)</span>
<span class="n">backend</span><span class="o">.</span><span class="n">default_compilation_pass</span><span class="p">()</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">measure0</span><span class="p">)</span>
<span class="n">backend</span><span class="o">.</span><span class="n">default_compilation_pass</span><span class="p">()</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">measure1</span><span class="p">)</span>

<span class="n">circ0</span> <span class="o">=</span> <span class="n">cu</span><span class="o">.</span><span class="n">circuit</span>
<span class="n">circ1</span> <span class="o">=</span> <span class="n">circ0</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
<span class="n">circ0</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">measure0</span><span class="p">)</span>
<span class="n">circ1</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">measure1</span><span class="p">)</span>
<span class="n">handles</span> <span class="o">=</span> <span class="n">backend</span><span class="o">.</span><span class="n">process_circuits</span><span class="p">([</span><span class="n">circ0</span><span class="p">,</span> <span class="n">circ1</span><span class="p">],</span> <span class="n">n_shots</span><span class="o">=</span><span class="p">[</span><span class="mi">4000</span><span class="p">,</span> <span class="mi">2000</span><span class="p">])</span>
<span class="n">r0</span><span class="p">,</span> <span class="n">r1</span> <span class="o">=</span> <span class="n">backend</span><span class="o">.</span><span class="n">get_results</span><span class="p">(</span><span class="n">handles</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">r0</span><span class="o">.</span><span class="n">get_counts</span><span class="p">())</span>
<span class="nb">print</span><span class="p">(</span><span class="n">r1</span><span class="o">.</span><span class="n">get_counts</span><span class="p">())</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-none notranslate"><div class="highlight"><pre><span></span>{(0, 0, 0, 0): 503, (0, 0, 0, 1): 488, (0, 1, 0, 0): 533, (0, 1, 0, 1): 493, (1, 0, 0, 0): 1041, (1, 0, 0, 1): 107, (1, 0, 1, 0): 115, (1, 0, 1, 1): 14, (1, 1, 0, 0): 576, (1, 1, 0, 1): 69, (1, 1, 1, 0): 54, (1, 1, 1, 1): 7}
{(0, 0, 0, 0): 2047, (0, 1, 0, 0): 169, (0, 1, 1, 0): 1729, (1, 1, 0, 0): 7, (1, 1, 1, 0): 48}
</pre></div>
</div>
</div>
</div>
</div>
<div class="section" id="measurement-reduction">
<h3>Measurement Reduction<a class="headerlink" href="#measurement-reduction" title="Permalink to this headline"></a></h3>
<p>Suppose we have one of these measurement scenarios (i.e. a single state preparation, but many measurements to make on it) and that each of the measurements is a Pauli observable, such as when calculating the expectation value of the state with respect to some <code class="xref py py-class docutils literal notranslate"><span class="pre">QubitPauliOperator</span></code>. Naively, we would need a different measurement <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> per term in the operator, but we can reduce this by exploiting the fact that commuting observables can be measured simultaneously.</p>
<p>Given a set of observables, we can partition them into subsets that are easy to measure simultaneously. A <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> is generated for each subset by diagonalising the observables (reducing all of them to a combination of <span class="math notranslate nohighlight">\(Z\)</span>-measurements).</p>
<p>Diagonalising a mutually commuting set of Pauli observables could require an arbitrary Clifford circuit in general. If we are considering the near-term regime where “every gate counts”, the diagonalisation of the observables could introduce more of the (relatively) expensive two-qubit gates, giving us the speedup at the cost of some extra noise. <code class="docutils literal notranslate"><span class="pre">pytket</span></code> can partition the Pauli observables into either general commuting sets for improved reduction in the number of measurement <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> s, or into smaller sets which can be diagonalised without introducing any multi-qubit gates - this is possible when all observables are substrings of some measured Pauli string (e.g. <cite>XYI</cite> and <cite>IYZ</cite> is fine, but <cite>ZZZ</cite> and <cite>XZX</cite> is not).</p>
<p>This measurement partitioning is built into the <code class="xref py py-meth docutils literal notranslate"><span class="pre">get_operator_expectation_value()</span></code> utility method, or can be used directly using <code class="xref py py-meth docutils literal notranslate"><span class="pre">pytket.partition.measurement_reduction()</span></code> which builds a <code class="xref py py-class docutils literal notranslate"><span class="pre">MeasurementSetup</span></code> object. A <code class="xref py py-class docutils literal notranslate"><span class="pre">MeasurementSetup</span></code> contains a list of measurement <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> s and a map from the <code class="xref py py-class docutils literal notranslate"><span class="pre">QubitPauliString</span></code> of each observable to the information required to extract the expectation value (which bits to consider from which <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code>).</p>
<div class="jupyter_cell jupyter_container docutils container">
<div class="cell_input code_cell docutils container">
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pytket</span> <span class="kn">import</span> <span class="n">Qubit</span>
<span class="kn">from</span> <span class="nn">pytket.pauli</span> <span class="kn">import</span> <span class="n">Pauli</span><span class="p">,</span> <span class="n">QubitPauliString</span>
<span class="kn">from</span> <span class="nn">pytket.partition</span> <span class="kn">import</span> <span class="n">measurement_reduction</span><span class="p">,</span> <span class="n">PauliPartitionStrat</span>
<span class="n">zi</span> <span class="o">=</span> <span class="n">QubitPauliString</span><span class="p">({</span><span class="n">Qubit</span><span class="p">(</span><span class="mi">0</span><span class="p">):</span><span class="n">Pauli</span><span class="o">.</span><span class="n">Z</span><span class="p">})</span>
<span class="n">iz</span> <span class="o">=</span> <span class="n">QubitPauliString</span><span class="p">({</span><span class="n">Qubit</span><span class="p">(</span><span class="mi">1</span><span class="p">):</span><span class="n">Pauli</span><span class="o">.</span><span class="n">Z</span><span class="p">})</span>
<span class="n">zz</span> <span class="o">=</span> <span class="n">QubitPauliString</span><span class="p">({</span><span class="n">Qubit</span><span class="p">(</span><span class="mi">0</span><span class="p">):</span><span class="n">Pauli</span><span class="o">.</span><span class="n">Z</span><span class="p">,</span> <span class="n">Qubit</span><span class="p">(</span><span class="mi">1</span><span class="p">):</span><span class="n">Pauli</span><span class="o">.</span><span class="n">Z</span><span class="p">})</span>
<span class="n">xx</span> <span class="o">=</span> <span class="n">QubitPauliString</span><span class="p">({</span><span class="n">Qubit</span><span class="p">(</span><span class="mi">0</span><span class="p">):</span><span class="n">Pauli</span><span class="o">.</span><span class="n">X</span><span class="p">,</span> <span class="n">Qubit</span><span class="p">(</span><span class="mi">1</span><span class="p">):</span><span class="n">Pauli</span><span class="o">.</span><span class="n">X</span><span class="p">})</span>
<span class="n">yy</span> <span class="o">=</span> <span class="n">QubitPauliString</span><span class="p">({</span><span class="n">Qubit</span><span class="p">(</span><span class="mi">0</span><span class="p">):</span><span class="n">Pauli</span><span class="o">.</span><span class="n">Y</span><span class="p">,</span> <span class="n">Qubit</span><span class="p">(</span><span class="mi">1</span><span class="p">):</span><span class="n">Pauli</span><span class="o">.</span><span class="n">Y</span><span class="p">})</span>

<span class="n">setup</span> <span class="o">=</span> <span class="n">measurement_reduction</span><span class="p">([</span><span class="n">zi</span><span class="p">,</span> <span class="n">iz</span><span class="p">,</span> <span class="n">zz</span><span class="p">,</span> <span class="n">xx</span><span class="p">,</span> <span class="n">yy</span><span class="p">],</span> <span class="n">strat</span><span class="o">=</span><span class="n">PauliPartitionStrat</span><span class="o">.</span><span class="n">CommutingSets</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Via Commuting Sets:&quot;</span><span class="p">)</span>
<span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">c</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">setup</span><span class="o">.</span><span class="n">measurement_circs</span><span class="p">):</span>
    <span class="nb">print</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">c</span><span class="o">.</span><span class="n">get_commands</span><span class="p">())</span>
<span class="nb">print</span><span class="p">(</span><span class="n">setup</span><span class="o">.</span><span class="n">results</span><span class="p">[</span><span class="n">yy</span><span class="p">])</span>

<span class="n">setup</span> <span class="o">=</span> <span class="n">measurement_reduction</span><span class="p">([</span><span class="n">zi</span><span class="p">,</span> <span class="n">iz</span><span class="p">,</span> <span class="n">zz</span><span class="p">,</span> <span class="n">xx</span><span class="p">,</span> <span class="n">yy</span><span class="p">],</span> <span class="n">strat</span><span class="o">=</span><span class="n">PauliPartitionStrat</span><span class="o">.</span><span class="n">NonConflictingSets</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Via Non-Conflicting Sets:&quot;</span><span class="p">)</span>
<span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">c</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">setup</span><span class="o">.</span><span class="n">measurement_circs</span><span class="p">):</span>
    <span class="nb">print</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">c</span><span class="o">.</span><span class="n">get_commands</span><span class="p">())</span>
<span class="nb">print</span><span class="p">(</span><span class="n">setup</span><span class="o">.</span><span class="n">results</span><span class="p">[</span><span class="n">yy</span><span class="p">])</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-none notranslate"><div class="highlight"><pre><span></span>Via Commuting Sets:
0 [Measure q[0] --&gt; c[0];, Measure q[1] --&gt; c[1];]
1 [CX q[0], q[1];, Measure q[1] --&gt; c[1];, H q[0];, Measure q[0] --&gt; c[0];]
[Circuit index: 1
Bits: 0 1 
Invert: True]
Via Non-Conflicting Sets:
0 [Measure q[0] --&gt; c[0];, Measure q[1] --&gt; c[1];]
1 [H q[0];, H q[1];, Measure q[0] --&gt; c[0];, Measure q[1] --&gt; c[1];]
2 [V q[0];, V q[1];, Measure q[0] --&gt; c[0];, Measure q[1] --&gt; c[1];]
[Circuit index: 2
Bits: 0 1 
Invert: False]
</pre></div>
</div>
</div>
</div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Since there could be multiple measurement <code class="xref py py-class docutils literal notranslate"><span class="pre">Circuit</span></code> s generating the same observable, we could theoretically use this to extract extra shots (and hence extra precision) for that observable for free; automatically doing this as part of <code class="xref py py-meth docutils literal notranslate"><span class="pre">measurement_reduction()</span></code> is planned for a future release of <code class="docutils literal notranslate"><span class="pre">pytket</span></code>.</p>
</div>
</div>
<div class="section" id="contextual-optimisations">
<h3>Contextual Optimisations<a class="headerlink" href="#contextual-optimisations" title="Permalink to this headline"></a></h3>
<p>By default, tket makes no assumptions about a circuit’s input state, nor about
the destiny of its output state. We can therefore compose circuits freely,
construct boxes from them that we can then place inside other circuits, and so
on. However, when we come to run a circuit on a real device we can almost always
assume that it will be initialised in the all-zero state, and that the final
state of the qubits will be discarded (after measurement).</p>
<p>This is where <cite>contextual optimisations</cite> can come into play. These are
optimisations that depend on knowledge of the context of the circuit being run.
They do not generally preserve the full unitary, but they generate circuits that
are observationally indistinguishable (on an ideal device), and reduce noise by
eliminating unnecessary operations from the beginning or end of the circuit.</p>
<p>First of all, tket provides methods to <cite>annotate</cite> a qubit (or all qubits) as
being initialized to zero, or discarded at the end of the circuit, or both.</p>
<div class="jupyter_cell jupyter_container docutils container">
<div class="cell_input code_cell docutils container">
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pytket</span> <span class="kn">import</span> <span class="n">Circuit</span>

<span class="n">c</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="n">c</span><span class="o">.</span><span class="n">Y</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="n">c</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">)</span>
<span class="n">c</span><span class="o">.</span><span class="n">H</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="n">c</span><span class="o">.</span><span class="n">H</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">c</span><span class="o">.</span><span class="n">Rz</span><span class="p">(</span><span class="mf">0.125</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">c</span><span class="o">.</span><span class="n">measure_all</span><span class="p">()</span>
<span class="n">c</span><span class="o">.</span><span class="n">qubit_create_all</span><span class="p">()</span>
<span class="n">c</span><span class="o">.</span><span class="n">qubit_discard_all</span><span class="p">()</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
</div>
</div>
<p>The last two lines tell the compiler that all qubits are to be initialized to
zero and discarded at the end. The methods <code class="xref py py-meth docutils literal notranslate"><span class="pre">Circuit.qubit_create()</span></code> and
<code class="xref py py-meth docutils literal notranslate"><span class="pre">Circuit.qubit_discard()</span></code> can be used to achieve the same on individual
qubits.</p>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>Note that we are now restricted in how we can compose our circuit with other circuits. When composing after another circuit, a “created” qubit becomes a Reset operation. Whem composing before another circuit, a “discarded” qubit may not be joined to another qubit unless that qubit has itself been “created” (so that the discarded state gets reset to zero).</p>
</div>
<div class="section" id="initial-simplification">
<h4>Initial simplification<a class="headerlink" href="#initial-simplification" title="Permalink to this headline"></a></h4>
<p>When the above circuit is run from an all-zero state, the Y and CX gates at the
beginning just have the effect of putting both qubits in the <span class="math notranslate nohighlight">\(\lvert 1
\rangle\)</span> state (ignoring unobservable global phase), so they could be replaced
with two X gates. This is exactly what the <code class="xref py py-meth docutils literal notranslate"><span class="pre">SimplifyInitial()</span></code> pass does.</p>
<div class="jupyter_cell jupyter_container docutils container">
<div class="cell_input code_cell docutils container">
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pytket.passes</span> <span class="kn">import</span> <span class="n">SimplifyInitial</span>

<span class="n">SimplifyInitial</span><span class="p">()</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">c</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">c</span><span class="o">.</span><span class="n">get_commands</span><span class="p">())</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-none notranslate"><div class="highlight"><pre><span></span>[X q[0];, X q[1];, H q[0];, H q[1];, Measure q[0] --&gt; c[0];, Measure q[1] --&gt; c[1];]
</pre></div>
</div>
</div>
</div>
<p>This pass tracks the state of qubits known to be initialised to zero (or reset
mid-circuit) forward through the circuit, for as long as the qubits remain in a
computational basis state, either removing gates (when they don’t change the
state) or replacing them with X gates (when they invert the state).</p>
<p>By default, this pass also replaces Measure operations acting on qubits with a
known state by classical set-bits operations on the target bits:</p>
<div class="jupyter_cell jupyter_container docutils container">
<div class="cell_input code_cell docutils container">
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">c</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">X</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">measure_all</span><span class="p">()</span>
<span class="n">c</span><span class="o">.</span><span class="n">qubit_create_all</span><span class="p">()</span>
<span class="n">SimplifyInitial</span><span class="p">()</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">c</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">c</span><span class="o">.</span><span class="n">get_commands</span><span class="p">())</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-none notranslate"><div class="highlight"><pre><span></span>[SetBits(1) c[0];, X q[0];]
</pre></div>
</div>
</div>
</div>
<p>The measurement has disappeared, replaced with a classical operation on its
target bit. To disable this behaviour, pass the <code class="docutils literal notranslate"><span class="pre">allow_classical=False</span></code>
argument to <code class="xref py py-meth docutils literal notranslate"><span class="pre">SimplifyInitial()</span></code> when constructing the pass.</p>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>Most backends currently do not support set-bit operations, so these could cause errors when using this pass with mid-circuit measurements. In such cases you should set <code class="docutils literal notranslate"><span class="pre">allow_classical=False</span></code>.</p>
</div>
<p>Note that <code class="xref py py-meth docutils literal notranslate"><span class="pre">SimplifyInitial()</span></code> does not automatically cancel successive
pairs of X gates introduced by the simplification. It is a good idea to follow
it with a <code class="xref py py-meth docutils literal notranslate"><span class="pre">RemoveRedundancies()</span></code> pass in order to perform these
cancellations.</p>
</div>
<div class="section" id="removal-of-discarded-operations">
<h4>Removal of discarded operations<a class="headerlink" href="#removal-of-discarded-operations" title="Permalink to this headline"></a></h4>
<p>An operation that has no quantum or classical output in its causal future has no
effect (or rather, no observable effect on an ideal system), and can be removed
from the circuit. By marking a qubit as discarded, we tell the compiler that it
has no quantum output, potentially enabling this simplification.</p>
<p>Note that if the qubit is measured, even if it is then discarded, the Measure
operation has a classical output in its causal future so will not be removed.</p>
<div class="jupyter_cell jupyter_container docutils container">
<div class="cell_input code_cell docutils container">
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pytket.circuit</span> <span class="kn">import</span> <span class="n">Qubit</span>
<span class="kn">from</span> <span class="nn">pytket.passes</span> <span class="kn">import</span> <span class="n">RemoveDiscarded</span>

<span class="n">c</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="n">c</span><span class="o">.</span><span class="n">H</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">H</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">H</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">Measure</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">Measure</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">H</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">H</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">c</span><span class="o">.</span><span class="n">qubit_discard</span><span class="p">(</span><span class="n">Qubit</span><span class="p">(</span><span class="mi">0</span><span class="p">))</span>
<span class="n">c</span><span class="o">.</span><span class="n">qubit_discard</span><span class="p">(</span><span class="n">Qubit</span><span class="p">(</span><span class="mi">2</span><span class="p">))</span>
<span class="n">RemoveDiscarded</span><span class="p">()</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">c</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">c</span><span class="o">.</span><span class="n">get_commands</span><span class="p">())</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-none notranslate"><div class="highlight"><pre><span></span>[H q[0];, H q[1];, CX q[0], q[1];, Measure q[0] --&gt; c[0];, Measure q[1] --&gt; c[1];, H q[1];]
</pre></div>
</div>
</div>
</div>
<p>The Hadamard gate following the measurement on qubit 0, as well as the Hadamard
on qubit 2, have disappeared, because those qubits were discarded. The Hadamard
following the measurement on qubit 1 remains, because that qubit was not
discarded.</p>
</div>
<div class="section" id="commutation-of-measured-classical-maps">
<h4>Commutation of measured classical maps<a class="headerlink" href="#commutation-of-measured-classical-maps" title="Permalink to this headline"></a></h4>
<p>The last type of contextual optimization is a little more subtle. Let’s call a
quantum unitary operation a <cite>classical map</cite> if it sends every computational
basis state to a computational basis state, possibly composed with a diagonal
operator. For example, X, Y, Z, Rz, CX, CY, CZ and Sycamore are classical maps,
but Rx, Ry and H are not. Check the
<a class="reference external" href="https://cqcl.github.io/tket/pytket/api/optype.html">documentation of gate types</a>
to see which gates have unitaries that make them amenable to optimisation.</p>
<p>When a classical map is followed by a measurement of all its qubits, and those
qubits are then discarded, it can be replaced by a purely classical operation
acting on the classical outputs of the measurement.</p>
<p>For example, if we apply a CX gate and then measure the two qubits, the result
is (ideally) the same as if we measured the two qubits first and then applied a
classical controlled-NOT on the measurement bits. If the gate were a CY instead
of a CX the effect would be identical: the only difference is the insertion of a
diagonal operator, whose effect is unmeasurable.</p>
<p>This simplification is effected by the <code class="xref py py-meth docutils literal notranslate"><span class="pre">SimplifyMeasured()</span></code> pass.</p>
<p>Let’s illustrate this with a Bell circuit:</p>
<div class="jupyter_cell jupyter_container docutils container">
<div class="cell_input code_cell docutils container">
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pytket.passes</span> <span class="kn">import</span> <span class="n">SimplifyMeasured</span>

<span class="n">c</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">H</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">measure_all</span><span class="p">()</span>
<span class="n">c</span><span class="o">.</span><span class="n">qubit_discard_all</span><span class="p">()</span>
<span class="n">SimplifyMeasured</span><span class="p">()</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">c</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">c</span><span class="o">.</span><span class="n">get_commands</span><span class="p">())</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-none notranslate"><div class="highlight"><pre><span></span>[Measure q[1] --&gt; c[1];, H q[0];, Measure q[0] --&gt; c[0];, ClassicalTransform c[0], c[1];]
</pre></div>
</div>
</div>
</div>
<p>The CX gate has disappeared, replaced with a classical transform acting on the
bits after the measurement.</p>
</div>
<div class="section" id="contextual-optimisation-in-practice">
<h4>Contextual optimisation in practice<a class="headerlink" href="#contextual-optimisation-in-practice" title="Permalink to this headline"></a></h4>
<p>The above three passes are combined in the <code class="xref py py-meth docutils literal notranslate"><span class="pre">ContextSimp()</span></code> pass, which
also performs a final <code class="xref py py-meth docutils literal notranslate"><span class="pre">RemoveRedundancies()</span></code>. Normally, before running a
circuit on a device you will want to apply this pass (after using
<code class="xref py py-meth docutils literal notranslate"><span class="pre">Circuit.qubit_create_all()</span></code> and <code class="xref py py-meth docutils literal notranslate"><span class="pre">Circuit.qubit_discard_all()</span></code> to
enable the simplifications).</p>
<p>However, most backends cannot process the classical operations that may be
introduced by <code class="xref py py-meth docutils literal notranslate"><span class="pre">SimplifyMeasured()</span></code> or (possibly)
<code class="xref py py-meth docutils literal notranslate"><span class="pre">SimplifyInitial()</span></code>. So pytket provides a method
<code class="xref py py-meth docutils literal notranslate"><span class="pre">separate_classical()</span></code> to separate the classical postprocessing circuit
from the main circuit to be run on the device. This postprocessing circuit is
then passed as the <code class="docutils literal notranslate"><span class="pre">ppcirc</span></code> argument to <code class="xref py py-meth docutils literal notranslate"><span class="pre">BackendResult.get_counts()</span></code> or
<code class="xref py py-meth docutils literal notranslate"><span class="pre">BackendResult.get_shots()</span></code>, in order to obtain the postprocessed
results.</p>
<p>Much of the above is wrapped up in the utility method
<code class="xref py py-meth docutils literal notranslate"><span class="pre">prepare_circuit()</span></code>. This takes a circuit, applies
<code class="xref py py-meth docutils literal notranslate"><span class="pre">Circuit.qubit_create_all()</span></code> and <code class="xref py py-meth docutils literal notranslate"><span class="pre">Circuit.qubit_discard_all()</span></code>,
runs the full <code class="xref py py-meth docutils literal notranslate"><span class="pre">ContextSimp()</span></code> pass, and then separates the result into
the main circuit and the postprocessing circuit, returning both.</p>
<p>Thus a typical usage would look something like this:</p>
<div class="jupyter_cell jupyter_container docutils container">
<div class="cell_input code_cell docutils container">
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pytket.utils</span> <span class="kn">import</span> <span class="n">prepare_circuit</span>
<span class="kn">from</span> <span class="nn">pytket.extensions.qiskit</span> <span class="kn">import</span> <span class="n">AerBackend</span>

<span class="n">b</span> <span class="o">=</span> <span class="n">AerBackend</span><span class="p">()</span>
<span class="n">c</span> <span class="o">=</span> <span class="n">Circuit</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span><span class="o">.</span><span class="n">H</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">CX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">c</span><span class="o">.</span><span class="n">measure_all</span><span class="p">()</span>
<span class="n">c0</span><span class="p">,</span> <span class="n">ppcirc</span> <span class="o">=</span> <span class="n">prepare_circuit</span><span class="p">(</span><span class="n">c</span><span class="p">)</span>
<span class="n">c0</span> <span class="o">=</span> <span class="n">b</span><span class="o">.</span><span class="n">get_compiled_circuit</span><span class="p">(</span><span class="n">c0</span><span class="p">)</span>
<span class="n">h</span> <span class="o">=</span> <span class="n">b</span><span class="o">.</span><span class="n">process_circuit</span><span class="p">(</span><span class="n">c0</span><span class="p">,</span> <span class="n">n_shots</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
<span class="n">r</span> <span class="o">=</span> <span class="n">b</span><span class="o">.</span><span class="n">get_result</span><span class="p">(</span><span class="n">h</span><span class="p">)</span>
<span class="n">shots</span> <span class="o">=</span> <span class="n">r</span><span class="o">.</span><span class="n">get_shots</span><span class="p">(</span><span class="n">ppcirc</span><span class="o">=</span><span class="n">ppcirc</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">shots</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="cell_output docutils container">
<div class="output stream highlight-none notranslate"><div class="highlight"><pre><span></span>[[1 1]
 [1 1]
 [0 0]
 [0 0]
 [0 0]
 [0 0]
 [1 1]
 [0 0]
 [1 1]
 [1 1]]
</pre></div>
</div>
</div>
</div>
<p>This is a toy example, but illustrates the principle. The actual circuit sent to
the backend consisted only of a Hadamard gate on qubit 0 and a single
measurement to bit 0. The classical postprocessing circuit set bit 1 to zero and
then executed a controlled-NOT from bit 0 to bit 1. These details are hidden
from us (unless we inspect the circuits), and what we end up with is a shots
table that is indistinguishable from running the original circuit but with less
noise.</p>
</div>
</div>
</div>
</div>


           </div>
          </div>
          <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer">
        <a href="manual_backend.html" class="btn btn-neutral float-left" title="Running on Backends" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a>
        <a href="manual_noise.html" class="btn btn-neutral float-right" title="Noise and the Quantum Circuit Model" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a>
    </div>

  <hr/>

  <div role="contentinfo">
    <p>&#169; Copyright 2020-2021 Cambridge Quantum Computing Ltd.</p>
  </div>

  Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
    <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
    provided by <a href="https://readthedocs.org">Read the Docs</a>.
   

</footer>
        </div>
      </div>
    </section>
  </div>
  <script>
      jQuery(function () {
          SphinxRtdTheme.Navigation.enable(true);
      });
  </script> 

</body>
</html>